MySQL快速插入百万行测试数据
整体思路:
- 1、如何产生大量数据?
可以利用循环,重复制造大量数据 - 2、如何快速将数据存储(插入)数据表?
直接使用循环也可以做到,但是速度可能会相对慢一点。可以利用MYSQL MEMORY引擎,加速数据的插入。
-- 1、创建内存表
-- 使用MEMORY数据库引擎,创建内存表。
-- 将数据直接插入内存表,再将数据从内存表复制到普通表,效率优于直接插入普通表
CREATE TABLE `table_in_memory` (
`id` INT(6) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`name` VARCHAR(50) NOT NULL COMMENT '名称',
`pwd` VARCHAR(32) NOT NULL COMMENT '密码',
`create_time` DATETIME DEFAULT NULL COMMENT '创建日期',
PRIMARY KEY (`id`)
) ENGINE=MEMORY AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8 COMMENT='内存临时表';
-- 2、创建使用MYISAM引擎的普通表,存放最终数据的表
-- 针对大量测试数据的这个场景,可以不考虑事务,因此可以使用MYISAM引擎
CREATE TABLE `test_data` (
`id` INT(6) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`name` VARCHAR(50) NOT NULL COMMENT '名称',
`pwd` VARCHAR(32) NOT NULL COMMENT '密码',
`create_time` DATETIME DEFAULT NULL COMMENT '创建日期',
PRIMARY KEY (`id`)
) ENGINE=MYISAM AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8 COMMENT='测试数据表';
-- 3、创建一个函数,用于生成随机数据
-- 尽管是测试数据,但是100W行一模一样的数据也就没有什么测试业务的价值。在创建测试数据的时候,使用一些算法,
-- 将数据尽量模拟真实一点。
DROP FUNCTION IF EXISTS rand_string;
DELIMITER $$
CREATE FUNCTION rand_string(n INT)
RETURNS VARCHAR(255)
BEGIN
DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
DECLARE return_str VARCHAR(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str = CONCAT(return_str,SUBSTRING(chars_str , FLOOR(1 + RAND()*62 ),1));
SET i = i +1;
END WHILE;
RETURN return_str;
END $$
DELIMITER ;
-- 4、创建存储过程,批量调用函数,生成大量随机数,并插入临时表(内存表)
DROP PROCEDURE IF EXISTS `add_data`;
DELIMITER $$
CREATE PROCEDURE `add_data`(IN n INT)
BEGIN
DECLARE i INT UNSIGNED DEFAULT 0;
WHILE i < n DO
INSERT INTO `table_in_memory`(NAME,pwd,create_time)
VALUES (rand_string(15),MD5(123456),NOW());
SET i = i+1;
END WHILE;
END $$
DELIMITER ;
-- 5、调用存储过程,调用之前最好先看一下,自己表最大存储量是多少,如果容量太少会导致,表爆满而插入失败。
-- 执行100W次的数据生成和插入。
-- 这里的时间依赖上面步骤中生成随机数的算法的效率,如果生成随机数的算法比较复杂,在100W次的执行中,
-- 也会比较耗时。另外和机器性能也有关。本机使用以上相对简单的随机数算法,执行了3次,平均1min 10sec左右
-- 完成100W行数据生成并插入内存表
CALL add_data(1000000);
-- 6、将内存表中的数据插入到普通表中
INSERT into test_data SELECT * from table_in_memory;
调用存储过程之前最好先看一下,自己表最大存储量是多少,如果容量太少会导致,表爆满而插入失败。
show variables like '%table_size'
将表容量改为1024M。在MYSQL安装路径下C:\ProgramData\MySQL\MySQL Server 8.0,找到my.ini配置文件,修改max_heap_table_size 参数的大小。如果不存在这个参数,直接添加
注意:ProgramData文件是隐藏的,要在查看中显示隐藏
max_heap_table_size = 1024M
重启数据库实例,让修改的配置生效。进入cmd 输入net stop mysql80
停掉服务,然后输入net start mysql80
启动服务
注意:MySQL8.0版本的要加80,不是8.0版本的不用,
重启后,查询show variables like '%table_size'
再次查看容量 。这是将表容量改为1024M后的显示
确定表容量够的话,再调用存储过程
CALL add_data(1000000);
遇到的问题
插入数据过慢,每秒插入几百条数据,插入一百万条数据耗时五十多分钟。正常每秒应该插入几千条数据(随机数算法,MD5算法比较耗时。如果没有用到这些算法更快,每秒一两万都可以)。
问题分析
MySQL8 默认是开启了bin_log日志,在执行插入的时候会保存日志比较耗时,另外有索引的话还要维护索引插入也会比较耗时。这里我们没用用到索引(如果有索引先关闭索引,插入后在开启索引就好了),所以我们直接关闭日志就好了 。
bin_log会一致保存,不会删除,导致占用大量的磁盘空间,在没有必要的情况下,可以禁用 bin_log 日志
1.首先我们查看一下bin_log 日志状态
show variables like 'log_%';
NO表示开启,OFF表示关闭。这里我已经关了,所以是OFF
-
关闭bin_log日志
找到MySQL的配置文件 my.ini文件,我的在C:\ProgramData\MySQL\MySQL Server 8.0\my.ini。注意(ProgramData是隐藏文件,要先在查看中打开隐藏才可以看到)
#添加一下任何一个即可 skip-log-bin disable-log-bin
-
修改了my.ini文件后,重启mysql服务。再次查看bin_log 日志状态:
show variables like 'log_%';
bin_log 日志就关闭了
在次插入十万条数据,只需要一分钟就好了。
补充:随机数算法,MD5算法比较耗时。下面是没用哪些算法,插入十万条数据只需要5秒钟就好了。