使用batch insert解决MySQL的insert吞吐量问题

最近使用了一个非常简单易用的方法解决了业务上的一个insert吞吐量的问题,在此总结一下。

首先我们明确一下,insert吞吐量其实并不是指的IPS(insert per second),而是指的RPS(effect rows per
second)。

其次我们再说一下batch insert,其实顾名思义,就是批量插入。这种优化思想是很基本的,MySQL中最出名的应用就是group
commit。

简单的来说,就是将SQL A 变成 SQL B

SQL A : insert into table values ($values);
SQL B : insert into table values ($values),($values)...($values);

下面,我们来看看这种异常简单的改动会带来什么样子的变化。

测试环境交代:单id的表结构,10w个int values,本地使用socket连接MySQL server,使用shell单进程测试。

首先,我们看下使用SQL A将10w个int values插入到test表中所需的耗时,耗时1777秒。

real    29m37.090s
user 9m11.705s
sys 5m0.762s

然后,我们看下使用SQL B(每次insert,插入10 values)将10w个int values插入到test表中所需的耗时,耗时53秒

real    0m53.871s
user 0m19.455s
sys 0m6.285s

这是整整近33倍的时间提升。这部分性能提升的原因在于以下几点:

1、每次和MySQL server建立连接都需要经过各种初始化、权限认证,语法解析等等多个步骤,需要消耗一定的资源。

2、更新一个values和更新n个values耗时基本一致。(下面对比一下insert 单values核insert 10
values的profile耗时)


单values:
+------------------------------+----------+
| Status | Duration |
+------------------------------+----------+
| starting | 0.000056 |
| checking permissions | 0.000010 |
| Opening tables | 0.000034 |
| System lock | 0.000010 |
| init | 0.000011 |
| update | 0.000061 |
| Waiting for query cache lock | 0.000003 |
| update | 0.000015 |
| end | 0.000003 |
| query end | 0.000053 |
| closing tables | 0.000009 |
| freeing items | 0.000021 |
| logging slow query | 0.000002 |
| cleaning up | 0.000003 |
+------------------------------+----------+

10 values:
+------------------------------+----------+
| Status | Duration |
+------------------------------+----------+
| starting | 0.000061 |
| checking permissions | 0.000008 |
| Opening tables | 0.000027 |
| System lock | 0.000008 |
| init | 0.000012 |
| update | 0.000073 |
| Waiting for query cache lock | 0.000003 |
| update | 0.000010 |
| end | 0.000008 |
| query end | 0.000053 |
| closing tables | 0.000010 |
| freeing items | 0.000021 |
| logging slow query | 0.000002 |
| cleaning up | 0.000003 |
+------------------------------+----------+

但是,是否values积攒的越多,效率越高吗? 答案自然是否定的,任何优化方案都不会是纯线性的,肯定会在某个条件下出现拐点。

我们按照不同的values number进行测试,分别为1、10、50、100、200、500、1000、5000、10000.

从下图我们可以看出,随着values number的增加,耗时先是急剧下降,从1777s变成53s,然后在增加values
number就不会有太大的变化,直到values number超过200,最后的10000个values number耗时达到了2分钟。

从下图我们可以看到随着values
numbers的增加,QPS(蓝线)先是猛增,然后下降,最终小于1/s。而RPS(绿线)随着增加猛增到一个高level,然后随着增加逐步下降,超过5000个values
number之后开始急剧下降。

另,最关键的是,QPS最高峰和RPS的最高峰并不在同一个values
number下,也就是说QPS最高的时候并不代表着insert的吞吐量就最高

在我这个简单测试场景中,values number最合适的值是50,和单values对比,耗时减少97%,insert吞吐量提升36倍

而这个值和表结构和字段类型及大小都有关系。需要根据不同的场景进行测试之后才可以得出,但是普遍来说,50-100是比较推荐的考虑值。

至于这个如何实现,只要前端写入的时候加入队列即可,可以按照2个条件进行合并

  • 队列中积攒到n个values
    number后在写入数据库,优点是性能最高,缺点是时间不可控,有可能等到第n个需要n秒,这时候业务已经不可接收了。

  • 队列中积攒1s之后,有多少个就写入多少个,优点是时间可控,缺点就是values
    number数目不可能,高并发的情况,可能1s已经积攒上千个values了。

  • 最优的方案其实是2个条件同时起作用,即进行个数效验,也进行时间效验,无论达到那个条件都触发后续写数据库操作。

总结:

1、使用batch insert可以提高insert的吞吐量。

2、叠加的values number需要根据实际情况测试得出。

3、同时使用个数和时间控制阀值。

附简单测试的记录值:




















































ValuesNum

Time

QPS

Rows

1

1777

56

56

10

53

188

1886

50

49

40

2040

100

50

19

2000

200

51

10

1960

500

57

3

1754

1000

60

2

1666

5000

69

0.3

1449

10000

133

0.07

751

使用batch insert解决MySQL的insert吞吐量问题

时间: 2024-10-24 00:45:59

使用batch insert解决MySQL的insert吞吐量问题的相关文章

mysql执行insert等语句报1205 Lock wait timeout exceeded try restarting transaction

mysql执行insert等语句是报如下错误: 1205 Lock wait timeout exceeded try restarting transaction 解决办法如下: 方法一:查看当前线程,是否有存在正在执行的你相关的语句,将其KILL  show processlist;  kill pid 方法二(方法一不行再执行):重启mysql数据库  service mysqld restart 注意:重启mysql会将在执行的线程全部kill

iOS Xcode, 解决“Could not insert new outlet connection”的问题。

在Xcode中,我们可以在StoryBoard编辑界面或者是xib编辑界面中通过“Control键+拖拽“的方式将某个界面元素和对应的代码文件连接起来,在代码文件中创建outlet. 不过,如果你的运气不太好,执行以上操作的过程中你可能会遇到下面这样的错误: 如图: Could not insert new outlet connection: Could not find any information for the class named "xxx". 其中的“xxx”就是你的目

MySQL的insert语句的区别

SQL Server: insert into tb_articleType (articleType_name,articleType_info) values ("test","test") insert into tb_articleType values ("test","test") MySQL: insert into tb_articleType (articleType_name,articleType_inf

MySQL 中文insert报错Incorrect string value: '\xCC\xEC\xB2\xC5'

    序言:中文录入失败,报错:Incorrect string value: '\xCC\xEC\xB2\xC5',如下所示:mysql> set names utf8;Query OK, 0 rows affected (0.00 sec) mysql> insert into t select 2 as a ,'天才' as b;ERROR 1366 (HY000): Incorrect string value: '\xCC\xEC\xB2\xC5' for column 'b' a

mysql 触发器,insert,auto字段竟然一样....

a 表的字段有id,uid,name,其中id是自增值, CREATE TRIGGER trigger_insert_productAFTER INSERT ON aFOR EACH ROWBEGIN insert into b (uid,name ) select NEW.id as db_goods_id ,  NEW.uid , NEW.name; END 上面的触发器当表a发生insert事件时,往表b中也插入要相同的数据,会发生表b的自增值跟表a一样, 真不知道为啥会这样, auto值

mysql 数据库插入语句之insert into,replace into ,insert ignore

最近才发现mysql的插入语句居然有如此多的用法,这里拿来分享一下. ①关于insert into : insert into table_name values(); insert into table_name (column) values (); insert into table_name values(select (column) from table_name2); 这里的插入只需要注意一点的就是: 如果发生主键冲突,(也就是插入的主键已经在表中存在时),系统报错. ②repla

MySQL数据库INSERT、UPDATE、DELETE以及REPLACE语句的用法详解

本篇文章是对MySQL数据库INSERT.UPDATE.DELETE以及REPLACE语句的用法进行了详细的分析介绍,需要的朋友参考下 MySQL数据库insert和update语句引:用于操作数据库的SQL一般分为两种,一种是查询语句,也就是我们所说的SELECT语句,另外一种就是更新语句,也叫做数据操作语句.言外之意,就是对数据进行修改.在标准的SQL中有3个语句,它们是INSERT.UPDATE以及DELETE. 用 于操作数据库的SQL一般分为两种,一种是查询语句,也就是我们所说的SEL

MySQL数据库insert和update语句

MySQL数据库insert和update语句 引:用于操作数据库的SQL一般分为两种,一种是查询语句,也就是我们所说的SELECT语句,另外一种就是更新语句,也叫做数据操作语句.言外之意,就是对数据进行修改.在标准的SQL中有3个语句,它们是INSERT.UPDATE以及DELETE. 用于操作数据库的SQL一般分为两种,一种是查询语句,也就是我们所说的SELECT语句,另外一种就是更新语句,也叫做数据操作语句.言外之意,就 是对数据进行修改.在标准的SQL中有3个语句,它们是INSERT.U

MySQL中INSERT INTO SELECT的使用

1. 语法介绍      有三张表a.b.c,现在需要从表b和表c中分别查几个字段的值插入到表a中对应的字段.对于这种情况,可以使用如下的语句来实现: INSERT INTO db1_name (field1,field2) SELECT field1,field2 FROM db2_name 上面的语句比较适合两个表的数据互插,如果多个表就不适应了.对于多个表,可以先将需要查询的字段JOIN起来,然后组成一个视图后再SELECT FROM就可以了: INSERT INTO a (field1,