记一次mysql大量插入数据,造成插入延迟,磁盘IO高的性能调优

Posted 敲代码的小小酥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次mysql大量插入数据,造成插入延迟,磁盘IO高的性能调优相关的知识,希望对你有一定的参考价值。

项目场景:

Kafka的数据入库到mysql中,由于业务场景的特殊性,Kafka并不是用于削峰填谷的,而是要求数据库尽可能的实时存入Kafka的最新数据。

问题描述:

虽然Kafka数据量巨大,但是过滤完数据后,消费者拉取的每批kafka数据只存入五六百条数据,但是随着时间的推移,存入数据与kafka的实时数据差距会越来越大。而且服务器磁盘IO也是将近100%。这可是服务器啊,就算插入五六百条数据也是毫秒级别的吧,为什么延迟会越来愈大呢?磁盘IO为何这么高呢?不应该吧

原因分析:

上面的问题,转化成两个问题来分析:
1.mysql如何进行大批量insert调优
2.mysql如何解决磁盘高IO问题。
按照上面两个问题,进行解决方案的设计。

解决方案:

一、mysql如何进行大批量insert调优
1. insert语句values后加多条数据,进行数据库批量插入。
起初的程序,确实是单条数据insert插入数据库的。当时认为一批数据五六百条,就算单条插入,数据库应该也是毫秒级别的插入吧,应该不会影响插入性能。后来验证后发现这个想法大错特错了。
手动复制了500条数据直接用navicat进行插入操作。结果发现,这500条insert语句,各自单条插入的时间确实很短,都是毫秒甚至纳秒级别的。但是,当500条insert语句顺序执行时,他们的执行是有先后顺序的,也就是说执行完一条后,才会执行另一条,不是并行执行的。所以,这就造成后面的sql需要等待前面的sql执行完后,才开始执行,这500条insert执行完总共用了十几秒的时间。在程序中也是一个道路,当一个连接循环insert语句时,后面的语句一定是等前面的语句执行完后才开始执行的。所以,处理完一批数据的五六百条数据后,已经花费了10几秒甚至更长的时间,这就造成了kafka下一次拉取数据其实等待了很长时间,所以造成了insert数据不能实时跟上kafka数据的问题。

2.关于bulk_insert_buffer_size参数的设置
网上很多博客说加大这个参数的值,允许insert语句拼接更多的values值。通过查看mysql官网描述可以知道,该参数是对MyISAM 引擎下的表才起作用的。而对于InnoDB引擎的表没有作用。所以设置该参数没有作用。

3.索引对插入数据的影响
随着表记录越来越多,索引对插入的性能影响也越来越大,所以,在批量插入数据时,可以把索引关闭,插入完成后,再将索引打开,如下:

ALTER TABLE my_table DISABLE KEYS;

-- Your insert statement

ALTER TABLE my_table ENABLE KEYS;

这种方式需要根据具体业务场景评估是否使用。因为频繁的开启或关闭索引会对查询造成影响。

4.利用列具有默认值的事实。仅当要插入的值与默认值不同时才显式插入值。这减少了 MySQL 必须做的解析并提高了插入速度。

  1. 更多insert性能调优,可以查看MYSQL官网:[InnoDB 表的批量数据加载]

实际上,我只听过修改了values后面加多个值的方式,解决了延迟的问题。

二、mysql如何解决磁盘高IO问题

解决磁盘IO问题,主要调整以下几个参数:
buffer pool size

innodb_io_capacity 参数

innodb_change_buffering参数

RAM

可参考mysql官网:优化 InnoDB 磁盘 I/O

以上是关于记一次mysql大量插入数据,造成插入延迟,磁盘IO高的性能调优的主要内容,如果未能解决你的问题,请参考以下文章

mysql 大量数据插入优化

mysql 大量数据插入优化

mysql 大量数据插入优化

记一次mysql中文字符乱码的问题排查

记一次MySQL注入绕过

记一次MySQL注入绕过