数据库批量数据插入问题分析
Posted 草莓王子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库批量数据插入问题分析相关的知识,希望对你有一定的参考价值。
在数据库的相关开发中,经常会遇到数据的批量插入问题。本文主要是通过实验的方式探讨批量数据插入的瓶颈,以及优化建议。
以10w条记录的插入作为实验对象,采用下面的几种方法插入:
1. 普通插入:普通的一条条插入
2. 普通插入+手动提交:setAutoCommit(false)、commit()
3. 普通插入+手动提交+ prepareStatement方式
4. 批量插入:addBatch、executeBatch
5. 批量插入:insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,
6. 多线程插入。
7. InnoDB引擎和MyISAM引擎的比较。
实验环境:
数据库:mysql 5.0
机器硬件:
内存 3G
CPU AMD双核4400+ 2.3G
首先建立一个简单的user表:
CREATE TABLE `user` (
`id` varchar(50) NOT NULL,
`seqid` bigint(20) NOT NULL auto_increment,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`seqid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
一、普通插入
代码:
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
2
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
3
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
4
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
5
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
6
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
7
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
8
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
9
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
10
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
11
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
12
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
13
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
输出结果:
commonInsert()执行时间为:13828ms
二、普通插入+手动提交:setAutoCommit(false)、commit()
代码:
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
2
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
3
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
4
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
5
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
6
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
7
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
8
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
9
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
10
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
11
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
12
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
13
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
14
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
15
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
输出结果:
commonInsert()执行时间为:13813ms
对比分析:
可以看出,仅仅是这种方式的设置,对性能的影响并不大。
三、普通插入+手动提交+ prepareStatement方式
代码:
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
2
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
3
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
4
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
5
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
6
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
7
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
8
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
9
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
10
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
11
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
12
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
13
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
14
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
15
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
输出结果:
prepareStatementInsert()执行时间为:12797ms
对比分析:
采用prepareStatement的方式确实可以提高一点性能,因为减少了数据库引擎解析优化SQL语句的时间,但是由于现在的插入语句太简单,所以性能提升不明显。
四、批量插入:addBatch、executeBatch
代码:
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
2
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
3
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
4
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
5
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
6
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
7
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
8
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
9
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
10
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
11
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
12
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
13
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
14
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
15
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
16
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
17
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
18
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
19
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
20
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
输出结果:
batchInsert()执行时间为:13625ms
对比分析:
按道理,这种批处理的方式是要快些的,但是测试结果却不尽人意,有点不解,请高人拍砖。
五、批量插入:insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,
代码:
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
2
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
3
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
4
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
5
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
6
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
7
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
8
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
9
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
10
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
11
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
12
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
13
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
14
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
15
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
16
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
17
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
18
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
19
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
20
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
21
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
22
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
23
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
输出结果:
manyInsert()执行时间为:937ms
对比分析:
发现采用这种方式的批量插入性能提升最明显,有10倍以上的性能提升。所以这种方式是我推荐的批量插入方式!
六、多线程插入
在第五种方式的基础上采用多线程插入。
代码:
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
2
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
3
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
4
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
5
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
6
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
7
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
8
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
9
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
10
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
11
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
12
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
13
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
14
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
15
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
16
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
17
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
18
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
19
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
20
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
21
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
22
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
23
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
24
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
25
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
26
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
27
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
28
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
29
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
30
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
31
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
32
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
33
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
34
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
35
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
36
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
37
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
38
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
39
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
输出结果:
multiThreadBatchInsert()执行时间为:2437ms
multiThreadBatchInsert()执行时间为:2625ms
multiThreadBatchInsert()执行时间为:2703ms
注意:上面我采用的是三个线程插入30w条数据。
取最大时间为2703ms,较上面的937ms,基本还是三倍的时间。
所以发现此时多线程也解决不了批量数据插入问题。原因就是,这时候的性能瓶颈不是CPU,而是数据库!
七、InnoDB引擎和MyISAM引擎的比较
最后,分析一下,这两个引擎对批量数据插入的影响。
先建立user2数据表:
CREATE TABLE `user2` (
`id` varchar(50) NOT NULL,
`seqid` bigint(20) NOT NULL auto_increment,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`seqid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
代码:
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
2
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
3
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
4
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
5
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
6
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
7
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockStart.gif)
8
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
9
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
10
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
11
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
12
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
13
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
14
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
15
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
16
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
17
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
18
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/InBlock.gif)
19
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/ExpandedBlockEnd.gif)
20
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
21
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
22
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
23
![技术分享](http://www.blogjava.net/Images/OutliningIndicators/None.gif)
输出结果:
manyInsert2()执行时间为:3484ms
注意:第七项的代码和第五是一样的,除了数据表名称不同(user、user2)
但是,
InnoDB :3484ms
MyISAM:937ms
所以,MyISAM引擎对大数据量的插入性能较好。
总结:
对于大数据量的插入,建议使用insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,的方式,引擎建议使用MyISAM引擎。
友情提醒:本博文章欢迎转载,但请注明出处:陈新汉
以上是关于数据库批量数据插入问题分析的主要内容,如果未能解决你的问题,请参考以下文章
MyBatis 批量插入包含 BLOB 类型的数据到 Oracle 异常问题分析