MYSQL批量插入数据库实现语句性能分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MYSQL批量插入数据库实现语句性能分析相关的知识,希望对你有一定的参考价值。

参考技术A   假定我们的表结构如下
代码如下

CREATE
TABLE
example
(
example_id
INT
NOT
NULL,
name
VARCHAR(
50
)
NOT
NULL,
value
VARCHAR(
50
)
NOT
NULL,
other_value
VARCHAR(
50
)
NOT
NULL
)
  通常情况下单条插入的sql语句我们会这么写:
代码如下

INSERT
INTO
example
(example_id,
name,
value,
other_value)
VALUES
(100,
'Name
1',
'Value
1',
'Other
1');
  mysql允许我们在一条sql语句中批量插入数据,如下sql语句:
代码如下

INSERT
INTO
example
(example_id,
name,
value,
other_value)
VALUES
(100,
'Name
1',
'Value
1',
'Other
1'),
(101,
'Name
2',
'Value
2',
'Other
2'),
(102,
'Name
3',
'Value
3',
'Other
3'),
(103,
'Name
4',
'Value
4',
'Other
4');
  如果我们插入列的顺序和表中列的顺序一致的话,还可以省去列名的定义,如下sql
代码如下

INSERT
INTO
example
VALUES
(100,
'Name
1',
'Value
1',
'Other
1'),
(101,
'Name
2',
'Value
2',
'Other
2'),
(102,
'Name
3',
'Value
3',
'Other
3'),
(103,
'Name
4',
'Value
4',
'Other
4');
  上面看上去没什么问题,下面我来使用sql语句优化的小技巧,下面会分别进行测试,目标是插入一个空的数据表200W条数据
  第一种方法:使用insert
into
插入,代码如下:
代码如下

$params
=
array('value'=>'50');
set_time_limit(0);
echo
date("H:i:s");
for($i=0;$i<2000000;$i++)
$connect_mysql->insert($params);
;
echo
date("H:i:s");
  最后显示为:23:25:05
01:32:05
也就是花了2个小时多!
  第二种方法:使用事务提交,批量插入数据库(每隔10W条提交下)最后显示消耗的时间为:22:56:13
23:04:00
,一共8分13秒
,代码如下:
代码如下

echo
date("H:i:s");
$connect_mysql->query('BEGIN');
$params
=
array('value'=>'50');
for($i=0;$i<2000000;$i++)
$connect_mysql->insert($params);
if($i%100000==0)
$connect_mysql->query('COMMIT');
$connect_mysql->query('BEGIN');


$connect_mysql->query('COMMIT');
echo
date("H:i:s");
  第三种方法:使用优化SQL语句:将SQL语句进行拼接,使用
insert
into
table
()
values
(),(),(),()然后再一次性插入,如果字符串太长,
  则需要配置下MYSQL,在mysql
命令行中运行
:set
global
max_allowed_packet
=
2*1024*1024*10;消耗时间为:11:24:06
11:25:06;
  插入200W条测试数据仅仅用了1分钟!代码如下:
代码如下

$sql=
"insert
into
twenty_million
(value)
values";
for($i=0;$i<2000000;$i++)
$sql.="('50'),";
;
$sql
=
substr($sql,0,strlen($sql)-1);
$connect_mysql->query($sql);
  最后总结下,在插入大批量数据时,第一种方法无疑是最差劲的,而第二种方法在实际应用中就比较广泛,第三种方法在插入测试数据或者其他低要求时比较合适,速度确实快。

MySQL批量SQL插入性能优化详解

对于一些数据量较大的系统,数据库面临的问题除了查询效率低下,还有就是数据入库时间长。特别像报表系统,每天花费在数据导入上的时间可能会长达几个小时或十几个小时之久。因此,优化数据库插入性能是很有意义的。
经过对MySQL innodb的一些性能测试,发现一些可以提高insert效率的方法,供大家参考参考。
1. 一条SQL语句插入多条数据。
常用的插入语句如:

INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘0‘, ‘userid_0‘, ‘content_0‘, 0);
INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘1‘, ‘userid_1‘, ‘content_1‘, 1);
修改成:

INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘0‘, ‘userid_0‘, ‘content_0‘, 0), (‘1‘, ‘userid_1‘, ‘content_1‘, 1);
修改后的插入操作能够提高程序的插入效率。这里第二种SQL执行效率高的主要原因是合并后日志量(MySQL的binlog和innodb的事务让 日志)减少了,降低日志刷盘的数据量和频率,从而提高效率。通过合并SQL语句,同时也能减少SQL语句解析的次数,减少网络传输的IO。
这里提供一些测试对比数据,分别是进行单条数据的导入与转化成一条SQL语句进行导入,分别测试1百、1千、1万条数据记录。

2. 在事务中进行插入处理。
把插入修改成:

START TRANSACTION;
INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘0‘, ‘userid_0‘, ‘content_0‘, 0);
INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘1‘, ‘userid_1‘, ‘content_1‘, 1);
...
COMMIT;
使用事务可以提高数据的插入效率,这是因为进行一个INSERT操作时,MySQL内部会建立一个事务,在事务内才进行真正插入处理操作。通过使用事务可以减少创建事务的消耗,所有插入都在执行后才进行提交操作。
这里也提供了测试对比,分别是不使用事务与使用事务在记录数为1百、1千、1万的情况。

3. 数据有序插入。
数据有序的插入是指插入记录在主键上是有序排列,例如datetime是记录的主键:

INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘1‘, ‘userid_1‘, ‘content_1‘, 1);
INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘0‘, ‘userid_0‘, ‘content_0‘, 0);
INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘2‘, ‘userid_2‘, ‘content_2‘,2);
修改成:

INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘0‘, ‘userid_0‘, ‘content_0‘, 0);
INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘1‘, ‘userid_1‘, ‘content_1‘, 1);
INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)
VALUES (‘2‘, ‘userid_2‘, ‘content_2‘,2);
由于数据库插入时,需要维护索引数据,无序的记录会增大维护索引的成本。我们可以参照innodb使用的B+tree索引,如果每次插入记录都在索 引的最后面,索引的定位效率很高,并且对索引调整较小;如果插入的记录在索引中间,需要B+tree进行分裂合并等处理,会消耗比较多计算资源,并且插入 记录的索引定位效率会下降,数据量较大时会有频繁的磁盘操作。
下面提供随机数据与顺序数据的性能对比,分别是记录为1百、1千、1万、10万、100万。

从测试结果来看,该优化方法的性能有所提高,但是提高并不是很明显。
性能综合测试:
这里提供了同时使用上面三种方法进行INSERT效率优化的测试。

从测试结果可以看到,合并数据+事务的方法在较小数据量时,性能提高是很明显的,数据量较大时(1千万以上),性能会急剧下降,这是由于此时数据量 超过了innodb_buffer的容量,每次定位索引涉及较多的磁盘读写操作,性能下降较快。而使用合并数据+事务+有序数据的方式在数据量达到千万级 以上表现依旧是良好,在数据量较大时,有序数据索引定位较为方便,不需要频繁对磁盘进行读写操作,所以可以维持较高的性能。
注意事项:
1. SQL语句是有长度限制,在进行数据合并在同一SQL中务必不能超过SQL长度限制,通过max_allowed_packet配置可以修改,默认是1M,测试时修改为8M。
2. 事务需要控制大小,事务太大可能会影响执行的效率。MySQL有innodb_log_buffer_size配置项,超过这个值会把innodb的数据刷到磁盘中,这时,效率会有所下降。所以比较好的做法是,在数据达到这个这个值前进行事务提交。

 

北京网站建设  http://www.wangzhanjianshegs.com/







































以上是关于MYSQL批量插入数据库实现语句性能分析的主要内容,如果未能解决你的问题,请参考以下文章

MYSQL批量插入数据库实现语句性能分析

向mysql中批量插入数据的性能分析

MySQL批量SQL插入性能优化

MySQL批量SQL插入性能优化

MySQL批量SQL插入性能优化详解

MySQL批量SQL插入各种性能优化