MariaDB - INNODB 在创建增量记录时跳过数字序列 - 为什么?

MariaDB - INNODB skipping the number sequence while creating incremental records - why?

我不知道这是否是 INNODB 的预期行为,但我真的认为这很奇怪。

如果我使用 MYISAM 使用相同的 SQL 语句,则行为会按预期发生。

MYISAM

CREATE TABLE main_database.numero (
    id INT NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY(id)
) ENGINE = MYISAM DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
INSERT INTO main_database.numero VALUES(NULL); -- First, run once time ...
INSERT INTO main_database.numero SELECT NULL FROM main_database.numero; -- After, more 12 times = 4096 records

结果(预期行为):

现在如果我使用完全相同的语句,但是,通知引擎是 INNODB

INNODB

CREATE TABLE main_database.numero (
    id INT NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY(id)
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

INSERT INTO main_database.numero VALUES(NULL); -- First, run once time ...
INSERT INTO main_database.numero SELECT NULL FROM main_database.numero; -- After, more 12 times = 4096 records

结果(奇怪的结果-跳过数字序列):

事实上,两个引擎都创建了预期的 4096 条记录,但我对 INNO 的行为感到担心,因为我正在将我的数据库从 MYISAM 迁移到 INNODB 并且我不知道这会对我的申请产生多大影响。

需要 auto_increment 机制来生成 唯一的 值,该值大于它之前生成的任何值。它不保证生成 个连续 个值。

这里有一些讨论:https://bugs.mysql.com/bug.php?id=57643

忠实地生成连续值并不重要,因为由于其他原因任何值都可能 "lost":

  • 您的 INSERT 失败,例如因为违反了 UNIQUE KEY 或 FOREIGN KEY 等约束。
  • 您回滚了 INSERT 的事务。
  • 您成功并提交,但稍后该行被您或其他会话删除。

A​​uto-inc 值不会返回到任何类型的队列,因为其他并发会话可能同时生成了更多的 id 值。 InnoDB 不值得维护一个未分配的 id 值池,因为该池可能变得巨大且浪费。

此外,"lose" ID 值可能是合适的,否则有人会认为他们打算删除的行不知何故又回来了。

To summarize the reason for this statement, it is a scheduling system that I have that uses this statement to create the calendar table.

不完全在您关于缺少 ID 的问题的范围内。
但是有更好的方法来生成数字和/或日历 table 然后重复 INSERT ... SELECT 多次。
所有方法都可以直接与其他table JOINed 或用于填充(索引)(临时)table

用于号码生成。

如果你的MariaDB/MySQL版本支持windows功能

SET SESSION cte_max_recursion_depth = 5000;

WITH RECURSIVE number_generator(number) AS (
  SELECT 0
  UNION ALL
  SELECT number + 1 FROM number_generator
  WHERE number BETWEEN 0 AND 4096
)
SELECT * FROM number_generator

对于不支持window功能的MariaDB/MySQL。

SELECT 
  number_generator.number
FROM (

SELECT 
 @row := @row + 1 AS number
FROM (
  SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) row1
CROSS JOIN (
  SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) row2
CROSS JOIN (
  SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) row3
CROSS JOIN (
   SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) row4
CROSS JOIN (
  SELECT @row := -1 
) init_user_params 
) AS number_generator
WHERE
 number_generator.number BETWEEN 0 AND 4096
ORDER BY 
 number_generator.number ASC

用于生成日历

如果你的MariaDB/MySQL版本支持windows功能

SET SESSION cte_max_recursion_depth = 5000;

WITH RECURSIVE number_generator(number) AS (
  SELECT 0
  UNION ALL
  SELECT number + 1 FROM number_generator
  WHERE number BETWEEN 0 AND 4096
)
SELECT CURRENT_DATE + INTERVAL number_generator.number DAY FROM number_generator

对于不支持window功能的MariaDB/MySQL。

SELECT 
  CURRENT_DATE + INTERVAL number_generator.number DAY
FROM (

SELECT 
 @row := @row + 1 AS number
FROM (
  SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) row1
CROSS JOIN (
  SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) row2
CROSS JOIN (
  SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) row3
CROSS JOIN (
  SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
) row4
CROSS JOIN (
  SELECT @row := -1 
) init_user_params 
) AS number_generator
WHERE
 number_generator.number BETWEEN 0 AND 4096
ORDER BY 
 number_generator.number ASC

CURRENT_DATE 只是一个示例,您也可以使用过去或未来的固定日期作为示例,您可以使用 '2019-03-01'

此外,+ INTERVAL number_generator.number DAY 也可以使用负数生成从该日期到过去的列表和其他值,然后 DAY 如果你想要月份,你可以使用 MONTH,想要您使用的年份 YEAR