MySQL: 为什么我的 INSERT 语句在自动递增 id 时会跳过 56 个数字?
MySQL: Why does my INSERT statement skip 56 numbers when auto-incrementing the id?
在向我的 SQL 课程的学生演示 INSERT 语句时,我们在 MySQL 8.0 中发现了一些奇怪的行为。请帮助我们了解正在发生的事情。 (不需要解决方法,因为我们知道一些,这是为了学习,而不是为了生产。谢谢)
我们正在创建一个新数据库并从众所周知的 Sakila 示例数据库中复制一些行,如下所示:
CREATE DATABASE simpsons;
USE simpsons;
CREATE TABLE `character` (
character_id smallint unsigned NOT NULL AUTO_INCREMENT,
first_name VARCHAR(20) NOT NULL,
last_name VARCHAR(20),
shoe_size INT,
PRIMARY KEY (character_id));
INSERT INTO `character`
(first_name, last_name)
SELECT
first_name, last_name
FROM
sakila.actor;
当我们这样做时,SELECT * FROM ``character``
我们看到 sakila.actor
中的所有 200 条记录都已正确复制到新的 character
table。
最后一行的 character_id
自动递增 PK 获得值 200
。输出 window 显示上述任何命令都没有错误。
然后,当我们立即手动添加一条记录时:
INSERT INTO `character`
(first_name, last_name, shoe_size)
VALUES
('Bart', 'Simpson', 35);
很奇怪,我们发现这条记录得到的值是 256
作为它的 character_id
而不是 201
。
尽管 运行 SHOW VARIABLES LIKE 'auto_inc%';
表明 auto_increment_increment
和 auto_increment_offset
都设置为 1
。
我们想了解为什么 MySQL 跳过 56 个数字?
请注意,这个问题与MySQL InnoDB auto_increment value increases by 2 instead of 1. Virus? and MySQL autoincrement column jumps by 10- why?不同,因为auto_incerement_increment
是1,在我们的(容易重现的)场景中没有DELETE操作,我们每个人都是唯一的我们未来数据库的用户。另外 none 该问题的答案对于实际发生的事情来说是决定性的。最后,请看@Postman 的精彩回答,其中提到了上述问题的任何回答中都没有提到的根本原因。谢谢
此行为与 "bulk inserts" and the innodb_autoinc_lock_mode
设置有关。
据我了解(文档对此不是很清楚),当您使用 INSERT INTO ... SELECT
语句时,MySQL 无法知道在 [ 之前实际插入了多少行=34=] 查询,但在使用 innodb_autoinc_lock_mode=1
(连续)或 2
(交错)时必须保留新 AUTO_INCREMENT 值的 ID。根据我的观察,它保留了一组 AUTO_INCREMENT 个数字,其中计数是 2 的幂(无法证实这一点,只是猜测)。请参阅以下示例:
CREATE TABLE sourceTable(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20)
);
CREATE TABLE targetTable(
id INT AUTO_INCREMENT PRIMARY KEY,
original VARCHAR(30)
);
INSERT INTO sourceTable(name) VALUES ('one');
INSERT INTO sourceTable(name) VALUES ('two');
INSERT INTO sourceTable(name) VALUES ('three');
INSERT INTO sourceTable(name) VALUES ('four');
INSERT INTO sourceTable(name) VALUES ('five');
INSERT INTO targetTable(original) SELECT name FROM sourceTable;
INSERT INTO targetTable(original) VALUES ('manual');
SELECT * FROM targetTable;
这将生成以下输出:
+----+----------+
| id | original |
+----+----------+
| 1 | one |
| 2 | two |
| 3 | three |
| 4 | four |
| 5 | five |
| 8 | manual |
+----+----------+
从源 table 插入 5 行时,它会保留接下来的 8 个可能的 AUTO_INCREMENT 值,因为这是大于 5 的最接近 2 的幂。但是,它只会使用其中 5 个,因为您只插入 5 行。
在您的例子中,您要插入 200 行,因此大于 200 的 2 的最接近幂为 256。因此您有 56 个 "gap" 缺失的 AUTO_INCREMENT 值和下一个条目获得 ID 256。
在向我的 SQL 课程的学生演示 INSERT 语句时,我们在 MySQL 8.0 中发现了一些奇怪的行为。请帮助我们了解正在发生的事情。 (不需要解决方法,因为我们知道一些,这是为了学习,而不是为了生产。谢谢)
我们正在创建一个新数据库并从众所周知的 Sakila 示例数据库中复制一些行,如下所示:
CREATE DATABASE simpsons;
USE simpsons;
CREATE TABLE `character` (
character_id smallint unsigned NOT NULL AUTO_INCREMENT,
first_name VARCHAR(20) NOT NULL,
last_name VARCHAR(20),
shoe_size INT,
PRIMARY KEY (character_id));
INSERT INTO `character`
(first_name, last_name)
SELECT
first_name, last_name
FROM
sakila.actor;
当我们这样做时,SELECT * FROM ``character``
我们看到 sakila.actor
中的所有 200 条记录都已正确复制到新的 character
table。
最后一行的 character_id
自动递增 PK 获得值 200
。输出 window 显示上述任何命令都没有错误。
然后,当我们立即手动添加一条记录时:
INSERT INTO `character`
(first_name, last_name, shoe_size)
VALUES
('Bart', 'Simpson', 35);
很奇怪,我们发现这条记录得到的值是 256
作为它的 character_id
而不是 201
。
尽管 运行 SHOW VARIABLES LIKE 'auto_inc%';
表明 auto_increment_increment
和 auto_increment_offset
都设置为 1
。
我们想了解为什么 MySQL 跳过 56 个数字?
请注意,这个问题与MySQL InnoDB auto_increment value increases by 2 instead of 1. Virus? and MySQL autoincrement column jumps by 10- why?不同,因为auto_incerement_increment
是1,在我们的(容易重现的)场景中没有DELETE操作,我们每个人都是唯一的我们未来数据库的用户。另外 none 该问题的答案对于实际发生的事情来说是决定性的。最后,请看@Postman 的精彩回答,其中提到了上述问题的任何回答中都没有提到的根本原因。谢谢
此行为与 "bulk inserts" and the innodb_autoinc_lock_mode
设置有关。
据我了解(文档对此不是很清楚),当您使用 INSERT INTO ... SELECT
语句时,MySQL 无法知道在 [ 之前实际插入了多少行=34=] 查询,但在使用 innodb_autoinc_lock_mode=1
(连续)或 2
(交错)时必须保留新 AUTO_INCREMENT 值的 ID。根据我的观察,它保留了一组 AUTO_INCREMENT 个数字,其中计数是 2 的幂(无法证实这一点,只是猜测)。请参阅以下示例:
CREATE TABLE sourceTable(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20)
);
CREATE TABLE targetTable(
id INT AUTO_INCREMENT PRIMARY KEY,
original VARCHAR(30)
);
INSERT INTO sourceTable(name) VALUES ('one');
INSERT INTO sourceTable(name) VALUES ('two');
INSERT INTO sourceTable(name) VALUES ('three');
INSERT INTO sourceTable(name) VALUES ('four');
INSERT INTO sourceTable(name) VALUES ('five');
INSERT INTO targetTable(original) SELECT name FROM sourceTable;
INSERT INTO targetTable(original) VALUES ('manual');
SELECT * FROM targetTable;
这将生成以下输出:
+----+----------+
| id | original |
+----+----------+
| 1 | one |
| 2 | two |
| 3 | three |
| 4 | four |
| 5 | five |
| 8 | manual |
+----+----------+
从源 table 插入 5 行时,它会保留接下来的 8 个可能的 AUTO_INCREMENT 值,因为这是大于 5 的最接近 2 的幂。但是,它只会使用其中 5 个,因为您只插入 5 行。
在您的例子中,您要插入 200 行,因此大于 200 的 2 的最接近幂为 256。因此您有 56 个 "gap" 缺失的 AUTO_INCREMENT 值和下一个条目获得 ID 256。