如何高效生成百万数据

文章顶图.png

派浪.png

背景

在工作中,我们大多需求中都会遇到对数据的新增的场景,如:批量生成测试数据、简单的数据迁移、统计数据报表等,如果一次性新增和修改的数据量特别大的时候,就会造成执行时间长而达不到我们的预期,往往令人头大。

那么应该如何快速生成百万数据呢,通常我们采用多线程的形式来加快代码的执行速度,但是如果换种方式呢,怎么样通过给单线程的方式给任务以最大的提升呢?以便后面多线程中,每个线程的速度都可以得到最大的提升,在这里我通过几种不同形式,给大家做个测试对比,看看哪种方式速度才更快。

技术使用

  • JAVA1.8
  • Mybatis
  • MySql5.7

准备工作

首先,我们准备一张简单的用户信息表,用于测试,表结构如下。

create table zcy_user
(
    id          int auto_increment primary key,
    user_name   varchar(32)  null,
    sex         int          null,
    email       varchar(50)  null,
    address     varchar(100) null,
    create_time timestamp    null
);

xml文件增加批量插入。

insert into t_user(`user_name`,`sex`,`email`,`address`) VALUES
<foreach collection="list" item="emp" separator=",">
  (#{emp.userName}, #{emp.sex}, #{emp.email} ,#{emp.address})
</foreach>

测试耗时

这里我们为了采用控制变量法来测试,采用单线程的形式,每次插入100万条数据,看看用时多久。

每次插入1条

由于每次插入1条数据耗时比较久,这里我们通过1万条数据耗时311.65秒,来估算出100万条数据约等于31165.70秒。

每次插入100条

每次插入100条数据耗373.58秒。

每次插入1000条

每次插入1000条数据耗62.08秒。

每次插入1万条

每次插入10000条数据耗31.83秒。

每次插入5万条

每次插入50000条数据耗29.30秒。

每次插入10万条

每次插入100000条数,这时候报错了,报错原因,上传大小数量大小5900064kb大于配置最大限制4194304kb(4M)。

对比

插入条数耗时/秒内存速度速度提倍率
131165空闲/
100373良好83倍
100062良好502倍
1000031中等1005倍
5000029较大1074倍
100000/很大//

拓展知识

Mysql内存结构

Mysql的官网中介绍了Innodb存储引擎结构包含了内存存储磁盘存储两部分,具体结构如下图所示。其中内存存储又包含了 Buffer Pool 和 Log Buffer。我们知道磁盘随机读写的效率很低,因此 Mysql 在设计的时候,读写的数据都优先读取到 Buffer Pool 中,之后再由 I/O 线程写入磁盘。

Buffer Pool

Mysql在设计的时候,为了避免每次访问都进行磁盘IO缓存表数据与索引数据,把磁盘上的一些经常被调用数据加载到缓冲池,起到加速访问的作用。那么是如何选择经常被调用的的数据呢,这里 Buffer Pool采用 LRU(Least recently used ,最近最少使用)算法来计算缓存中的存储数据。但是在普通的LRU算法中,如果有个SQL请求是查询某个表的全量数据,在进行深度分页的时候,其实每次都会获取前几页的数据,这样最后缓存中只会存下分页的前几也数据,然而这些数据并不是真正意义上的调用频率最高的数据,这样就导致缓存空间没有真实的利用起来。

根据上边的分析,Mysql 在设计的时候对 LRU 做了优化,在原来 LRU 拆分的基础上,又加了冷热数据的区分,把原来的空间的 3/8 存储冷数据,5/8 的空间存储热数据;那么具体是怎么判断出来冷热数据呢,根据 Mysql 的配置中可以看出,访问数据间隔1秒作为分界线,连续请求时间小于 1 秒的数据通过 LRU 算法将数据移动到冷数据的最前端;连续请求时间大于1秒的则将数据分配到热数据中去。通过这样的改造来保证缓存数据中的存储的是热数据。

#查看冷热数据区分时间 1000ms
mysql> show variables like 'innodb_old_blocks_time';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_old_blocks_time | 1000  |
+------------------------+-------+
1 row in set (0.00 sec)

Change Buffer

这里我们拿更新为例,当需要更新的数据数据页在 Chang Buffer 中时,数据页在内存中就直接更新。如果数据页不在内存中。在不影响数据一致性的前提下,InooDB 会将这些更新操作缓存在 Change Buffer 中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。这样操作可以把多次操作通过 merge 形式合并后提交,提高了执行性能。如果执行失败,或者系统意外中断,也可以通过 Redo Log 来重心执行任务,保证数据正确。

性能提升原理分析

合并事务

上述测试的数据,insert values 其实就是多条 insert value 的事务合并到一起提交。对于 Mysql 而言,每次的事务就会生成一条对应的 Redo Log,当多个命令合并到一个事务中的时候,就可以减少磁盘的 IO 次数,以提升性能;但是日志文件的大小是有上限的,超过配置的最大值后,性能就不会巨大提升了。

#写入values保证一个事务
insert into t_user(`user_name`,`sex`,`email`,`address`) VALUES
(1,1,1,1),(2,2,2,2)…………(n,n,n,n);

#多个value写入一个事务
begin;
insert into t_user(`user_name`,`sex`,`email`,`address`) value(1,1,1,1);
insert into t_user(`user_name`,`sex`,`email`,`address`) value(2,2,2,2);
…………
insert into t_user(`user_name`,`sex`,`email`,`address`) value(n,n,n,n);
commit;

保证数据顺序

我们知道数据在磁盘中是以文件形式存储,Innodb 引擎采用B+树索引存储,是有顺序的,如果插入索引是连续的,那么在次盘搜索时候会在同一片连续空间中进行顺序 IO 操作,反之索引是乱序的,会造成次盘扫描的时候进行随机 IO,这样的代价是什么高昂的。因此我们在生成数据的索引值尽量为 id 或者规律的数据,保证新增的时候能够在连续空间中存储。

使用场景

  • 数据报表导入
  • 批量初始化数据
  • 百万千万数据迁移
  • 日志表记录

总结

现在的很多工程项目中,数据量过百万已经是很常见的了,但是性能还需要得到保障,根据测试结果分析后,批量生成数据的时候,可以根据业务场景尽可能能把可以合并的请求合并到同一个事务中,这样可以提升不少的性能,给我们的数据库和服务减少压力,让程序更加稳定。

推荐阅读

政采云Flutter低成本屏幕适配方案探索

Redis系列之Bitmaps

MySQL 之 InnoDB 锁系统源码分析

招贤纳士

政采云技术团队(Zero),一个富有激情、创造力和执行力的团队,Base 在风景如画的杭州。团队现有300多名研发小伙伴,既有来自阿里、华为、网易的“老”兵,也有来自浙大、中科大、杭电等校的新人。团队在日常业务开发之外,还分别在云原生、区块链、人工智能、低代码平台、中间件、大数据、物料体系、工程平台、性能体验、可视化等领域进行技术探索和实践,推动并落地了一系列的内部技术产品,持续探索技术的新边界。此外,团队还纷纷投身社区建设,目前已经是 google flutter、scikit-learn、Apache Dubbo、Apache Rocketmq、Apache Pulsar、CNCF Dapr、Apache DolphinScheduler、alibaba Seata 等众多优秀开源社区的贡献者。如果你想改变一直被事折腾,希望开始折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊……如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的技术团队的成长过程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 zcy-tc@cai-inc.com

微信公众号

文章同步发布,政采云技术团队公众号,欢迎关注

文章顶图.png