我试图将大量用户插入到具有两个表的MySQL数据库中:
第一个表包含用户数据.示例INSERT
如下所示(id
是主键,mail
是唯一键):
INSERT INTO users (id, mail, name)
VALUES (NULL, "foo@bar.tld", "John Smith")
ON DUPLICATE KEY UPDATE name = VALUE(name)
Run Code Online (Sandbox Code Playgroud)
第二个表包含用户所属的组.它只存储两个外键users_id
和groups_id
.示例查询如下所示:
INSERT INTO users_groups (users_id, groups_id)
VALUES (LAST_INSERT_ID(), 1)
Run Code Online (Sandbox Code Playgroud)
此设置适用于小型数据集.当我导入大量数据(> 1M行)时,INSERT
s变慢.显然,进行批量插入会好得多:
INSERT INTO users (id, mail, name)
VALUES (NULL, "foo@bar.tld", "John Smith"), (NULL, "baz@qux.tld", "Anna Smith")
ON DUPLICATE KEY UPDATE name = VALUE(name)
Run Code Online (Sandbox Code Playgroud)
和:
INSERT INTO users_groups (users_id, groups_id)
VALUES (LAST_INSERT_ID(), 1), (LAST_INSERT_ID(), 4)
Run Code Online (Sandbox Code Playgroud)
问题当然是,LAST_INSERT_ID()
只返回批处理的一个(第一个)id INSERT
.
所以,我需要的是一个"嵌套"批处理INSERT
,IMO在MySQL中不存在.
我能做些什么才能让我INSERT
的速度更快?
默认情况下,批量插入提供顺序自动增量,有了这些知识,您可以执行插入操作;
INSERT INTO users (id, mail, name)
VALUES (NULL, "foo@bar.tld", "John Smith"),
(NULL, "baz@qux.tld", "Anna Smith"),
(...) # repeat n-times
;
SET @LASTID=LAST_INSERT_ID()
;
INSERT INTO users_groups (users_id, groups_id)
VALUES (@LASTID - n , 1), # Note n in descending sequence
(@LASTID - n-1, 1),
...
(@LASTID - 1 , 1),
(@LASTID - 0 , 4)
;
Run Code Online (Sandbox Code Playgroud)
有关批量插入和自动增量的更多信息,请查看http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html
重要的是,请确保innodb_autoinc_lock_mode = 1
show global variables like 'innodb_autoinc_lock_mode'
Run Code Online (Sandbox Code Playgroud)
否则请考虑包装插件 LOCK TABLES
LOCK TABLES tbl_name WRITE
... sqls ...
UNLOCK TABLES
Run Code Online (Sandbox Code Playgroud)