MySQL插入优化-性能对比

devtools/2024/10/17 17:54:40/

插入优化主要包括:

  1. 批量插入条数据,而不是单个记录逐条插入。
  2. 手动提交事务,避免自动提交事务带来的额外开销。
  3. 使用load命令从本地文件导入。

性能对比

创建数据库

mysql">CREATE TABLE if not exists `tb_sku`  
(  `id`            int(20)        NOT NULL primary key AUTO_INCREMENT,  `sn`            varchar(64)    NOT NULL,  `name`          varchar(64)    NOT NULL,  `price`         decimal(10, 2) NOT NULL,  `stock`         int(11)        NOT NULL,  `create_time`   timestamp      NOT NULL DEFAULT CURRENT_TIMESTAMP,  `update_time`   timestamp      NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  `category_name` varchar(64)    NOT NULL,  `brand_name`    varchar(64)    NOT NULL,  `status`        tinyint(4)     NOT NULL DEFAULT '1',  `description`   varchar(1024)           DEFAULT NULL  
);

1. 单条插入自动提交事务

创建存储过程构建数据

mysql">drop procedure if exists `insertSkuData`;  
DELIMITER //  
create procedure `insertSkuData`(in num int)  
begin  declare i int default 1;  declare sn varchar(64);  declare name varchar(64);  declare sql_stmt TEXT;  -- 临时表作为数组,目的是为了随机取值  CREATE TABLE if not exists `tmp_name`  (  id     int primary key auto_increment,  t_name varchar(64)  );  insert into tmp_name(t_name)  values ('华为Mate60'),  ('华为Mate70'),  ('华为Mate80'),  ('华为Mate90'),  ('华为Mate100'),  ('华为Mate110'),  ('华为Mate120'),  ('华为Mate130'),  ('华为Mate140'),  ('华为Mate150');  insert into tmp_name(t_name)  values ('小米Mate60'),  ('小米Mate70'),  ('小米Mate80'),  ('小米Mate90'),  ('小米Mate100'),  ('小米Mate110'),  ('小米Mate120'),  ('小米Mate130'),  ('小米Mate140'),  ('小米Mate150');  insert into tmp_name(t_name)  values ('oppoMate60'),  ('oppoMate70'),  ('oppoMate80'),  ('oppoMate90'),  ('oppoMate100'),  ('oppoMate110'),  ('oppoMate120');  while i <= num  do  SET sql_stmt = 'insert into tb_sku(sn, name, price, stock, category_name, brand_name, description) values';  SET sn = UPPER(REPLACE(UUID(), '-', ''));  SET name = (select t_name from tmp_name order by rand() limit 1);  SET sql_stmt = CONCAT(sql_stmt, '(\'', sn, '\',\'', name, '\',', 999.0, ',', 100, ',', '\'手机\'', ',\'',  SUBSTR(name, 1, 2), '\',', '\'由存储过程insertSkuData生成\'', ')');  -- 执行SQL语句  set @sql_stmt = sql_stmt;  prepare stmt from @sql_stmt;  execute stmt;  deallocate prepare stmt;  SET i = i + 1;  end while;    drop table if exists tmp_name;  
end//  DELIMITER ;  call insertSkuData(1000000);

执行结果耗时:2m52s
在这里插入图片描述

2. 单条插入手动提交事务

创建存储过程构建数据

mysql">drop procedure if exists `insertSkuData`;  
DELIMITER //  
create procedure `insertSkuData`(in num int)  
begin  declare i int default 1;  declare sn varchar(64);  declare name varchar(64);  declare sql_stmt TEXT;  -- 临时表作为数组,目的是为了随机取值  CREATE TABLE if not exists `tmp_name`  (  id     int primary key auto_increment,  t_name varchar(64)  );  insert into tmp_name(t_name)  values ('华为Mate60'),  ('华为Mate70'),  ('华为Mate80'),  ('华为Mate90'),  ('华为Mate100'),  ('华为Mate110'),  ('华为Mate120'),  ('华为Mate130'),  ('华为Mate140'),  ('华为Mate150');  insert into tmp_name(t_name)  values ('小米Mate60'),  ('小米Mate70'),  ('小米Mate80'),  ('小米Mate90'),  ('小米Mate100'),  ('小米Mate110'),  ('小米Mate120'),  ('小米Mate130'),  ('小米Mate140'),  ('小米Mate150');  insert into tmp_name(t_name)  values ('oppoMate60'),  ('oppoMate70'),  ('oppoMate80'),  ('oppoMate90'),  ('oppoMate100'),  ('oppoMate110'),  ('oppoMate120');  -- 手动提交事务,将所有数据作为一次事务提交  start transaction ;  while i <= num  do  SET sql_stmt = 'insert into tb_sku(sn, name, price, stock, category_name, brand_name, description) values';  SET sn = UPPER(REPLACE(UUID(), '-', ''));  SET name = (select t_name from tmp_name order by rand() limit 1);  SET sql_stmt = CONCAT(sql_stmt, '(\'', sn, '\',\'', name, '\',', 999.0, ',', 100, ',', '\'手机\'', ',\'',  SUBSTR(name, 1, 2), '\',', '\'由存储过程insertSkuData生成\'', ')');  -- 执行SQL语句  set @sql_stmt = sql_stmt;  prepare stmt from @sql_stmt;  execute stmt;  deallocate prepare stmt;  SET i = i + 1;  end while;    commit ;    drop table if exists tmp_name;  
end//  DELIMITER ;  call insertSkuData(1000000);

执行结果耗时:1m7s:
在这里插入图片描述

3. 批量插入自动提交事务

创建存储过程构建数据:

mysql">drop procedure if exists `insertSkuData`;  
DELIMITER //  
create procedure `insertSkuData`(in num int)  
begin  declare i int default 1;  declare j int default 1;  declare batch_size int default 10;  declare cnt int default 0;  declare sn varchar(64);  declare name varchar(64);  declare sql_stmt TEXT;  -- 计算批次,比如10000条记录,则分10批次,一个批次1000条记录插入数据  if MOD(num, batch_size) = 0 then  set cnt = num / batch_size;  else        set cnt = num / batch_size + 1;  end if;  -- 临时表作为数组,目的是为了随机取值  CREATE TABLE if not exists `tmp_name`  (  id     int primary key auto_increment,  t_name varchar(64)  );  insert into tmp_name(t_name)  values ('华为Mate60'),  ('华为Mate70'),  ('华为Mate80'),  ('华为Mate90'),  ('华为Mate100'),  ('华为Mate110'),  ('华为Mate120'),  ('华为Mate130'),  ('华为Mate140'),  ('华为Mate150');  insert into tmp_name(t_name)  values ('小米Mate60'),  ('小米Mate70'),  ('小米Mate80'),  ('小米Mate90'),  ('小米Mate100'),  ('小米Mate110'),  ('小米Mate120'),  ('小米Mate130'),  ('小米Mate140'),  ('小米Mate150');  insert into tmp_name(t_name)  values ('oppoMate60'),  ('oppoMate70'),  ('oppoMate80'),  ('oppoMate90'),  ('oppoMate100'),  ('oppoMate110'),  ('oppoMate120');  while i <= cnt  do  if i = cnt then  set batch_size = num - (cnt - 1) * batch_size;  end if;  SET sql_stmt = 'insert into tb_sku(sn, name, price, stock, category_name, brand_name, description) values';  SET j = 1;  while j <= batch_size  do  SET sn = UPPER(REPLACE(UUID(), '-', ''));  SET name = (select t_name from tmp_name order by rand() limit 1);  SET sql_stmt =  CONCAT(sql_stmt, '(\'', sn, '\',\'', name, '\',', 999.0, ',', 100, ',', '\'手机\'', ',\'',  SUBSTR(name, 1, 2), '\',', '\'由存储过程insertSkuData生成\'', ')');  IF j < batch_size THEN  SET sql_stmt = CONCAT(sql_stmt, ', ');  END IF;  SET j = j + 1;  end while;  -- 执行SQL语句  set @sql_stmt = sql_stmt;  prepare stmt from @sql_stmt;  execute stmt;  deallocate prepare stmt;  SET i = i + 1;  end while;drop table if exists tmp_name;  
end//  DELIMITER ;  
call insertSkuData(1000000);

执行结果耗时:1m5s:
在这里插入图片描述

4. 批量插入手动提交事务

创建存储过程构建数据:

mysql">drop procedure if exists `insertSkuData`;  
DELIMITER //  
create procedure `insertSkuData`(in num int)  
begin  declare i int default 1;  declare j int default 1;  declare batch_size int default 10;  declare cnt int default 0;  declare sn varchar(64);  declare name varchar(64);  declare sql_stmt TEXT;  -- 计算批次,比如10000条记录,则分10批次,一个批次1000条记录插入数据  if MOD(num, batch_size) = 0 then  set cnt = num / batch_size;  else        set cnt = num / batch_size + 1;  end if;  -- 临时表作为数组,目的是为了随机取值  CREATE TABLE if not exists `tmp_name`  (  id     int primary key auto_increment,  t_name varchar(64)  );  insert into tmp_name(t_name)  values ('华为Mate60'),  ('华为Mate70'),  ('华为Mate80'),  ('华为Mate90'),  ('华为Mate100'),  ('华为Mate110'),  ('华为Mate120'),  ('华为Mate130'),  ('华为Mate140'),  ('华为Mate150');  insert into tmp_name(t_name)  values ('小米Mate60'),  ('小米Mate70'),  ('小米Mate80'),  ('小米Mate90'),  ('小米Mate100'),  ('小米Mate110'),  ('小米Mate120'),  ('小米Mate130'),  ('小米Mate140'),  ('小米Mate150');  insert into tmp_name(t_name)  values ('oppoMate60'),  ('oppoMate70'),  ('oppoMate80'),  ('oppoMate90'),  ('oppoMate100'),  ('oppoMate110'),  ('oppoMate120');  -- 整个数据作为一次事务提交  start transaction ;  while i <= cnt  do  if i = cnt then  set batch_size = num - (cnt - 1) * batch_size;  end if;  SET sql_stmt = 'insert into tb_sku(sn, name, price, stock, category_name, brand_name, description) values';  SET j = 1;  while j <= batch_size  do  SET sn = UPPER(REPLACE(UUID(), '-', ''));  SET name = (select t_name from tmp_name order by rand() limit 1);  SET sql_stmt =  CONCAT(sql_stmt, '(\'', sn, '\',\'', name, '\',', 999.0, ',', 100, ',', '\'手机\'', ',\'',  SUBSTR(name, 1, 2), '\',', '\'由存储过程insertSkuData生成\'', ')');  IF j < batch_size THEN  SET sql_stmt = CONCAT(sql_stmt, ', ');  END IF;  SET j = j + 1;  end while;  -- 执行SQL语句  set @sql_stmt = sql_stmt;  prepare stmt from @sql_stmt;  execute stmt;  deallocate prepare stmt;  SET i = i + 1;  end while;    commit;    drop table if exists tmp_name;  
end//  DELIMITER ;  
call insertSkuData(1000000);

执行结果耗时:45s:
在这里插入图片描述

Note:批量插入的大小根据物理性能而定。

  1. 可以在插入数据前,禁用唯一性检查,结束后开启
mysql">-- 关闭唯一性检查
SET UNIQUE_CHECKS=0;-- 开启
SET UNIQUE_CHECKS=1;
  1. 可以在插入数据前,禁用外键检查,结束后开启
mysql">-- 关闭外键检查
SET FOREIGN_KEY_CHECKS=0;-- 开启
SET FOREIGN_KEY_CHECKS=1;

不过上面两种优化实测没有明显优化。

总结:

  1. 手动提交事务可以很大程度优化数据插入。
  2. 批量插入优化的批次大小视情况而定。

单条自动提交事务 < 单条手动提交事务 ≈ 批量插入自动提交事务 < 批量插入手动提交事务


http://www.ppmy.cn/devtools/126518.html

相关文章

基于Java的可携宠物酒店管理系统的设计与实现(论文+源码)_kaic

摘 要 随着社会经济的不断发‎‏展&#xff0c;现如今出行并住酒店的人越来越多&#xff0c;与之而来的是酒店行业的工作量日益增加&#xff0c;酒店的管理效率亟待提升。此外很多人出门旅游时会有携带宠物的情况&#xff0c;但是现如今酒店对宠物的限制&#xff0c;导致许多…

西门子网络程序传输,无需开通网络驱动器直接接入底层,支持各类数控 如发那科、三菱 、新代、海德汉、广数、精雕、马扎克等等

有关西门子的程序传输问题&#xff0c;大家一般是通过文件共享、ftp、网络驱动器等方式&#xff0c;其中828D还需要授权开通网络启动器 下面介绍一种方式直接进入西门子Linux底层系统实现和NCK的文件交互功能 软件截图如下 功能表如下 机床程序上载至电脑 电脑程序下传…

IO进程---day3

1、完成标准io的单字符实现两个文件的拷贝&#xff1b; #include<myhead.h>//标准io的单字符现两个文件的拷贝&#xff1b; int main(int argc, const char *argv[]) {//判断是否有3个文件传入if(3 ! argc){fputs("input file error\n",stderr);return -1;}//打…

构建高效购物推荐系统:SpringBoot实战

1系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#xff0c;这种种好处使得互联网成了信息传…

【C++】STL--stack

1. stack的介绍 stack的文档介绍 后进先出&#xff08;LIFO&#xff09;&#xff1a;Stack容器遵循后进先出的原则&#xff0c;即最后进入栈的元素最先被移出栈。 2.stack的使用 常用的几个接口 代码演示如下 int main() {stack<int> st;st.push(1);st.push(2);st.…

在Windows中使用谷歌浏览器观看和录制游戏直播

在现代数字娱乐时代&#xff0c;游戏直播已经成为许多玩家和观众的重要娱乐方式。使用谷歌浏览器在Windows系统中观看和录制游戏直播不仅方便&#xff0c;还能提供高质量的观看体验。本文将为大家详细介绍如何使用谷歌浏览器进行这一操作。&#xff08;本文由https://google.ch…

关于oracle数据库/加载机密码中含有特殊字符@:><等的解决办法

一、前提交代 我最近项目中需要通过把特定的数据文件(.gz文件)导入到oracle库中&#xff0c;一般情况我们是通过shell来实现该功能&#xff0c;然后再通过作业调度调用shell来实现。在shell中肯定要连接数据库和加载机&#xff08;存放数据文件的服务器&#xff09;,但是数据库…

OceanBase 的写盘与传统数据库有什么不同?

背景 在数据库开发过程中&#xff0c;“写盘”是一项核心操作&#xff0c;即将内存中暂存的数据安全地转储到磁盘上。在诸如MySQL这样的传统数据库管理系统中&#xff0c;写盘主要有以下几步&#xff1a;首先将数据写入缓存池&#xff1b;其次&#xff0c;为了确保数据的完整性…