当我将多行插入 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 ever 以 3) 或 4) 或任何其他结尾组合?如果是(我总是以 1)
或 2)
结尾),MyISAM
和 InnoDB
?
如果我这样做 SELECT LAST_INSERT_ID();
并且例如我得到 7
,它是否自动意味着带有 id
8
和 9
的行也被 我的查询 插入而不是通过另一个人的查询?
如果你定义任何列的主键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
设置:
- 传统 (0)
- 顺序 (1) - 默认
- 交错 (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.
已测试
如果我有如下查询:
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 ever 以 3) 或 4) 或任何其他结尾组合?如果是(我总是以 1)
或 2)
结尾),MyISAM
和 InnoDB
?
如果我这样做 SELECT LAST_INSERT_ID();
并且例如我得到 7
,它是否自动意味着带有 id
8
和 9
的行也被 我的查询 插入而不是通过另一个人的查询?
如果你定义任何列的主键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
设置:
- 传统 (0)
- 顺序 (1) - 默认
- 交错 (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.
已测试