当我将多行插入 MySQL table 时,id 是否每次都递增 1?

When I INSERT multiple rows into a MySQL table, will the ids be increment by 1 everytime?

如果我有如下查询:

INSERT INTO table (col1,col2,col3) VALUES
('col1_value_1', 'col2_value_1', 'col3_value_1'),
('col1_value_2', 'col2_value_2', 'col3_value_2'),
('col1_value_3', 'col2_value_3', 'col3_value_3');

假设我有一个 table,其中最后一个 id PRIMARY_KEY AUTO_INCREMENT 的值是 56,那么这个插入查询总是会创建 3 条记录ID 57, 58, 59。这个操作是原子操作吗?

或者,如果另一个查询写在同一个 table 上,ids 不会总是递增 1 吗?

感谢关注!

编辑:请阅读以下内容,因为我可能不太清楚。

当然AUTO_INCREMENT加1是安全的,我知道。

重点是:

假设我有以下 table 称为 table:

 ___________________________________
| id | col1       | col2             |
-------------------------------------
|  1 | "some val" | "some other val" |
|  2 | "some val" | "some other val" |
|  3 | "some val" | "some other val" |
|  4 | "some val" | "some other val" |
|  5 | "some val" | "some other val" |
|  6 | "some val" | "some other val" |
|____________________________________|

如果我知道 运行 查询:

INSERT INTO table (col1,col2) VALUES
('some val', 'some other val'),
('some val', 'some other val'),
('some val', 'some other val')

我将得到以下结果 table:

 ___________________________________
| id | col1       | col2             |
-------------------------------------
|  1 | "some val" | "some other val" |
|  2 | "some val" | "some other val" |
|  3 | "some val" | "some other val" |
|  4 | "some val" | "some other val" |
|  5 | "some val" | "some other val" |
|  6 | "some val" | "some other val" |
|  7 | "some val" | "some other val" |
|  8 | "some val" | "some other val" |
|  9 | "some val" | "some other val" |
|____________________________________|

这里没什么好说的。但是如果我和另一个人运行同时进行同一个查询,这些查询是atomic吗?也就是说我们会always结束于:

1)

 ___________________________________
| id | col1       | col2             |
-------------------------------------
|  1 | "some val" | "some other val" |
|  2 | "some val" | "some other val" |
|  3 | "some val" | "some other val" |
|  4 | "some val" | "some other val" |
|  5 | "some val" | "some other val" |
|  6 | "some val" | "some other val" |
|  7 | "some val" | "some other val" |<-- My 1st inserted record
|  8 | "some val" | "some other val" |<-- My 2nd inserted record
|  9 | "some val" | "some other val" |<-- My 3rd inserted record
| 10 | "some val" | "some other val" |<-- Another guy's 1st inserted record
| 11 | "some val" | "some other val" |<-- Another guy's 2nd inserted record
| 12 | "some val" | "some other val" |<-- Another guy's 3rd inserted record
|____________________________________|

或与:

2)

 ___________________________________
| id | col1       | col2             |
-------------------------------------
|  1 | "some val" | "some other val" |
|  2 | "some val" | "some other val" |
|  3 | "some val" | "some other val" |
|  4 | "some val" | "some other val" |
|  5 | "some val" | "some other val" |
|  6 | "some val" | "some other val" |
|  7 | "some val" | "some other val" |<-- Another guy's 1st inserted record
|  8 | "some val" | "some other val" |<-- Another guy's 2nd inserted record
|  9 | "some val" | "some other val" |<-- Another guy's 3rd inserted record
| 10 | "some val" | "some other val" |<-- My 1st inserted record
| 11 | "some val" | "some other val" |<-- My 2nd inserted record
| 12 | "some val" | "some other val" |<-- My 3rd inserted record
|____________________________________|

取决于两个 MySQL 计划中的哪个查询优先。

还是会出现以下异常?:

3)

 ___________________________________
| id | col1       | col2             |
-------------------------------------
|  1 | "some val" | "some other val" |
|  2 | "some val" | "some other val" |
|  3 | "some val" | "some other val" |
|  4 | "some val" | "some other val" |
|  5 | "some val" | "some other val" |
|  6 | "some val" | "some other val" |
|  7 | "some val" | "some other val" |<-- My 1st inserted record
|  8 | "some val" | "some other val" |<-- My 2nd inserted record
|  9 | "some val" | "some other val" |<-- Another guy's 1st inserted record - WTF???
| 10 | "some val" | "some other val" |<-- My 3rd inserted record 
| 11 | "some val" | "some other val" |<-- Another guy's 2nd inserted record
| 12 | "some val" | "some other val" |<-- Another guy's 3rd inserted record
|____________________________________|

或者像这样:

4)

 ___________________________________
| id | col1       | col2             |
-------------------------------------
|  1 | "some val" | "some other val" |
|  2 | "some val" | "some other val" |
|  3 | "some val" | "some other val" |
|  4 | "some val" | "some other val" |
|  5 | "some val" | "some other val" |
|  6 | "some val" | "some other val" |
|  7 | "some val" | "some other val" |<-- Another guy's 1st inserted record
|  8 | "some val" | "some other val" |<-- My 1st inserted record - WTF???
|  9 | "some val" | "some other val" |<-- Another guy's 2nd inserted record
| 10 | "some val" | "some other val" |<-- My 2nd inserted record - WTF^2???
| 11 | "some val" | "some other val" |<-- Another guy's 3rd inserted record
| 12 | "some val" | "some other val" |<-- My 3rd inserted record - WTF^3???
|____________________________________|

或任何其他组合 != 3)4)?

我认为 1)2) 是原子的。 总是保证我会总是1)2结束)never ever3)4) 或任何其他结尾组合?如果是(我总是以 1)2) 结尾),MyISAMInnoDB?

如果我这样做 SELECT LAST_INSERT_ID(); 并且例如我得到 7,它是否自动意味着带有 id 89 的行也被 我的查询 插入而不是通过另一个人的查询?

如果你定义任何列的主键aut_increment那么它会自动从1开始增加值, 您不需要在插入查询中定义此列,它会自动在主键列中插入增量值。

auto_increment 并发环境 中是安全的。它的工作是提供独特的价值,无论您联系了多少人并在 table 上工作。您可以控制递增的偏移量,默认为1

现在这实际上是什么意思 - 这意味着 table 中 写的 不必加 1。这就是著名的 "gap"问题。

假设你和我同时给你的table写信。我写了记录10, 11, 12,你写了13, 14, 15。但是,可能发生了一些不好的事情(死锁或事务失败)并且我的结果没有保留 - 查询失败并且 auto_increment 被花掉了。在这种情况下,您的记录 (13, 14, 15) 会写入磁盘,而我的不会。

这是正常行为。您的 table 不必包含递增 1 的数字。它将包含 唯一的 数字,这就是 auto_increment.

的工作

答案是:嗯,视情况而定。

对于 myisam,答案肯定是肯定的,因为 myisam 对插入请求进行排序。

然而,在 innodb 的情况下,该行为自 mysql v5.1 以来是可配置的。在 v5.1 之前,InnoDB 的答案也是肯定的,之后它取决于 innodb_autoinc_lock_mode 设置。请参阅有关 InnoDB auto_increment configuration for details 的 mysql 文档。

为了给你亮点,有3个innodb_autoinc_lock_mode设置:

  1. 传统 (0)
  2. 顺序 (1) - 默认
  3. 交错 (2)

With innodb_autoinc_lock_mode set to 0 (“traditional”) or 1 (“consecutive”), the auto-increment values generated by any given statement will be consecutive, without gaps, because the table-level AUTO-INC lock is held until the end of the statement, and only one such statement can execute at a time.

With innodb_autoinc_lock_mode set to 2 (“interleaved”), there may be gaps in the auto-increment values generated by “bulk inserts,” but only if there are concurrently executing “INSERT-like” statements.

For lock modes 1 or 2, gaps may occur between successive statements because for bulk inserts the exact number of auto-increment values required by each statement may not be known and overestimation is possible.

如果事务已回滚,则可以在 auto_increment 值中体验更多差距。批量插入只能作为一个整体回滚。

更新: 如上所述,你会得到场景1)或2),如果你使用

  • myisam table 引擎
  • 或 innodb pre mysql v5.1
  • 或带有 mysql v5.1 或更新版本的 innodb,并且 innodb_autoinc_lock_mode 是 0 或 1

无法判断哪个先插入。

如果您使用

,您可能会遇到场景3)或4)
  • innodb 与 innodb_autoinc_lock_mode 2

同样,无法说明 mysql 如何以及为什么混淆了记录的顺序。

因此,如果您的问题与您使用批量插入插入 3 条记录并且 last_insert_id() returns 仅第一个插入记录的 auto_increment 值有关,并且您想通过简单的加法获得其他 2 条记录的 ID,您可能需要根据使用的 table 引擎和 mysql 版本检查 mysql 的配置。

mysql 将多插入查询视为一个事务或一个查询,将插入所有行,或者如果失败则不会插入任何行,因此如果插入此查询:

INSERT INTO table (col1,col2,col3) VALUES
('col1_value_1', 'col2_value_1', 'col3_value_1'),
('col1_value_2', 'col2_value_2', 'col3_value_2'),
('col1_value_3', 'col2_value_3', 'col3_value_3');

mysql 将 运行 这作为一个查询,如果您的 ID 自动递增,它将占用您的 ID 57、58、59。 如果其他用户同时通过插入查询,则如果其他用户查询比您的查询花费更多时间,则您的查询将花费 57、58、59 的概率,如果您的查询花费的时间比其他用户多,那么您的 ID 将开始来自其他用户查询端。因此,无论如何,当 id 为自动增量时,多插入查询将在查询中排序。

如果您在一个语句中插入值,场景 3 和 4 即使您正在使用它们也不会出现 innodb_autoinc_lock_mode = 2。来自文档 https://dev.mysql.com/doc/refman/5.7/en/innodb-auto-increment-handling.html

innodb_autoinc_lock_mode = 2 In this lock mode, auto-increment values are guaranteed to be unique and monotonically increasing across all concurrently executing “INSERT-like” statements.

已测试