关于INSERT效率的问题引发的同步延迟

设想

最近研发侧在做数据导入的改造,改造的方式是将原来LOAD DATA的方式修改为INSERT插入的方式,主要基于如下两方面考虑:

1、修改成INSERT后能更方便地在程序侧控制写入的线程数,更好地保护后端DB,防止后端DB雪崩

2、减少大批量导入带来DB的延迟(单个LOAD拆分成多个INSERT,多线程同步)

另外监控DB大部分的load数据量都比较小,改成INSERT对导入延迟影响不会太大。

下面是对INSERT和LOAD DATA的方式做的简单的测试结果:

从上面的测试结果,批量INSERT 30000条数据只比LOAD DATA的方式慢了2倍多一点,如果将30000的数据拆分成1000一个批量INSERT的SQL,并发写入,耗时比单线程LOAD要有提升。

上线遇到的问题

上线后,平均耗时增长了很多,如下图所示:

并且深入去看,耗时比较高的都是跨IDC的机器(上海写深圳),而且高得离谱。

从上图中,可以看到,耗时比较大的都是上海的机器。

并且监控DB的主从延迟也有比较大的飙升,如下图:

奇怪,按照之前的计算评估,不应该会有那么大的延迟,而且同步延迟应该有缓解才对,不可能越来越厉害。

分析和解决问题

查看监控发现INSERT出现了暴增,如下图:

针对insert,改写成1000条一次的并发插入,正常也不应该有那么大的增长,怀疑是INSERT INTO的方式不是采用批量的方式,而是一条一条insert的方式。分析binlog发现执行方式如下:

BEGIN;

INSERT INTO TABLENAME VALUES('X','X','X');

INSERT INTO TABLENAME VALUES('X','X','X');

INSERT INTO TABLENAME VALUES('X','X','X');

.......

COMMIT;

这种方式和单个INSERT的方式性能差别其实并不算大,下面是简单的测试结果:

测试场景: 在跨机房场景下,延迟相对比较大,30ms左右,测试INSERT本身的性能

1、INSERT 单行

2、INSERT 单行多values

3、INSERT 多行(27行)

4、INSERT 多行(27行)在一个事务中

测试接入过如下图:

可以看出:

采用INSERT 多values的形式和插入单行差别不算大(主要是行数不多);

采用INSERT多行和把多个INSERT放到一个大事务中性能相差不大。

解决办法就很简单了,直接把大事务修改为INSERT多values的方式。

修改后,INSERT的量大幅度下降:

平均耗时也大幅下降:

同步延迟也逐渐恢复:

总结

在写入效率上,对比关系如下:

1、LOAD DATA效率最高

2、INSERT 多values次之

3、INSERT 多行大事务再次之

4、INSERT 单行最差

你可能感兴趣的:(关于INSERT效率的问题引发的同步延迟)