使用LAST_INSERT_ID()在多个表上进行MySQL批量插入

Hor*_*ren 9 mysql database

我试图将大量用户插入到具有两个表的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_idgroups_id.示例查询如下所示:

INSERT INTO users_groups (users_id, groups_id)
VALUES (LAST_INSERT_ID(), 1)
Run Code Online (Sandbox Code Playgroud)

此设置适用于小型数据集.当我导入大量数据(> 1M行)时,INSERTs变慢.显然,进行批量插入会好得多:

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的速度更快?

har*_*vey 6

默认情况下,批量插入提供顺序自动增量,有了这些知识,您可以执行插入操作;

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)

  • 来自问题的`INSERT`查询具有`ON DUPLICATE KEY UPDATE`子句.如果`id`是表的唯一`UNIQUE`索引,那么该子句是无害的,不需要.但是如果表上有另一个`UNIQUE`索引(在`mail` fe列上)并且在'INSERT`期间发生了重复键,则所有这些`LAST_INSERT_ID()`都是错误的,因为在这种情况下``id`是递增但未使用(现有行已更新). (2认同)