问题描述:

普通台式机,采集数据,表中已经有>1000万数据量。
采集回来的数据插入表中的时候很慢,每条约100毫秒。

解决方法:

1、加大mysql配置中的bulk_insert_buffer_size,这个参数默认为8M

bulk_insert_buffer_size=100M

2、改写所有insert into语句为insert delayed into

这个insert delayed不同之处在于:立即返回结果,后台进行处理插入。

3、还有一个技巧是在一条insert中插入多条数据,类似insert into tablename values('xxx','xxx'),('yyy','yyy'),('zzz','zzz')...;但是在我采集程序中改sql比较麻烦,故未采用

 插入记录时,影响插入速度的主要是索引、唯一性校验、一次插入记录条数等。根据这些情况,可以分别进行优化,本节将介绍优化插入记录速度的几种方法。

一.对于MyISAM引擎表常见的优化方法如下:

    1.禁用索引。对于非空表插入记录时,MySQL会根据表的索引对插入记录建立索引。如果插入大量数据,建立索引会降低插入记录的速度。为了解决这种情况可以在插入记录之前禁用索引,数据插入完毕后在开启索引。禁用索引的语句为: ALTER TABLE tb_name DISABLE KEYS;  重新开启索引的语句为: ALTER TABLE table_name ENABLE KEYS; 对于空表批量导入数据,则不需要进行此操作,因为MyISAM引擎的表是在导入数据之后才建立索引的。
    2.禁用唯一性检查:数据插入时,MySQL会对插入的记录进行唯一性校验。这种唯一性校验也会降低插入记录的速度。为了降低这种情况对查询速度的影响,可以在插入记录之前禁用唯一性检查,等到记录插入完毕之后再开启。禁用唯一性检查的语句为: SET UNIQUE_CHECKS=0; 开启唯一性检查的语句为: SET UNIQUE_CHECKS=1;
    3.使用批量插入。使用一条INSERT语句插入多条记录。如 INSERT INTO table_name VALUES(....),(....),(....)
    4.使用LOAD DATA INFILE批量导入 当需要批量导入数据时,使用LOAD DATA INFILE语句导入数据的速度比INSERT语句快。

二.对于InnoDB引擎的表,常见的优化方法如下:

1. 禁用唯一性检查。

同MyISAM引擎相同,通过 SET global UNIQUE_CHECKS=0;  导入数据之后将该值置1。

2. 禁用外键检查。

插入数据之前执行禁止对外键的查询,数据插入完成之后再恢复对外键的检查。禁用外键检查语句为: 
       SET global FOREIGN_KEY_CHECKS=0; 
恢复对外键的检查语句为: SET FOREIGN_KEY_CHECKS=1;

3. 禁止自动提交。

插入数据之前禁止事务的自动提交,数据导入完成之后,执行恢复自动提交操作。禁止自动提交语句为: SET AUTOCOMMIT=0;  恢复自动提交只需将该值置1。

4. 禁止时时同步日志到磁盘

set global innodb_flush_log_at_trx_commit=2;  #禁止时时同步日志到磁盘

5.  配置max_allowed_packet为1G

max_allowed_packet=1073741824;  配置max_allowed_packet为1G

6.   

innodb_io_capacity   =2000                                                                                     
innodb_io_capacity_max  =20000  

7.

vim /etc/my.cnf   ->innodb_flush_method=O_DIRECT

8. 将 innodb_autoextend_increment 配置由于默认8M 调整到 128M 

 innodb_autoextend_increment=128

此配置项作用主要是当tablespace 空间已经满了后,需要MySQL系统需要自动扩展多少空间,每次tablespace 扩展都会让各个SQL 处于等待状态。增加自动扩展Size可以减少tablespace自动扩展次数。

9.将 innodb_log_buffer_size 配置由于默认1M 调整到 128M 

innodb_log_buffer_size=128M

此配置项作用设定innodb 数据库引擎写日志缓存区;将此缓存段增大可以减少数据库写数据文件次数。

10.将 innodb_log_file_size 配置由于默认 8M 调整到 128M 

innodb_log_file_size=128M

此配置项作用设定innodb 数据库引擎UNDO日志的大小;从而减少数据库checkpoint操作。 11.锁定表-禁用键-启用键-解锁表

--锁定表
LOCK TABLES `erp_order_2018` WRITE;
--禁用键
ALTER TABLE  erp_order_2018 DISABLE  KEYS ;
--插入数据
INSERT INTO `erp_order_2018` VALUES (1,11,'UPDATED');
INSERT INTO `erp_order_2018 ` VALUES (2,11,'UPDATED');
--启用键
ALTER TABLE `erp_order_2018 ` ENABLE KEYS;
--解锁表
UNLOCK TABLES;

12.删除表上所有的索引:

ALTER TABLE `table_name` DROP INDEX `column`;

三、结论

经过以上调整,系统插入速度由于原来10分钟几万条提升至1秒1W左右;

注:以上参数调整,需要根据不同机器来进行实际调整。特别是 innodb_flush_log_at_trx_commit、innodb_log_buffer_size和 innodb_log_file_size 需要谨慎调整;因为涉及MySQL本身的容灾处理。 

 最后生效的my.cnf配置:

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
innodb_buffer_pool_size = 6144M
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
join_buffer_size = 200M
sort_buffer_size = 10M
read_rnd_buffer_size = 5M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
max_allowed_packet=1073741824
bulk_insert_buffer_size=100M
innodb_log_buffer_size=128M
innodb_log_file_size=128M
innodb_autoextend_increment=100
innodb_flush_method=O_DIRECT
innodb_io_capacity=2000
innodb_io_capacity_max=20000
innodb_flush_log_at_trx_commit=2