MariaDB - INNODB пропускает числовую последовательность при создании добавочных записей - почему?

Я не знаю, ожидаемое ли это поведение с INNODB, но я действительно думаю, что это совершенно странно.

Если я использую тот же оператор 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.

ИННОДБ

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 и не знаю, насколько это может повлиять на мои приложения.


person Magno Alberto    schedule 08.03.2019    source источник
comment
Может быть вставка, которую откатили?   -  person Lasse V. Karlsen    schedule 08.03.2019
comment
Эта схема абсолютно чистая/новая, никто не обращается к ней и не записывает ее. По вашему вопросу, я не знаю, по какой причине сама MariaDB выполняет откат.   -  person Magno Alberto    schedule 08.03.2019
comment
Это не имеет смысла. Вы пытались поместить все 34 INSERT в одну транзакцию?   -  person IVO GELOV    schedule 08.03.2019
comment
Извините, но я думаю, что это не имеет значения, имеет ли это смысл или нет, так как оператор отлично работает с MYISAM. Но да, я использую этот оператор для создания цикла в одном операторе.   -  person Magno Alberto    schedule 08.03.2019
comment
Иногда MySQL спотыкается. Не беспокойтесь о пропущенных числах.   -  person Strawberry    schedule 08.03.2019
comment
Ладно...конечно могу и подкорректирую заявление, но мне очень хотелось иметь возможность понять такое поведение или хотя бы причину такой реакции.   -  person Magno Alberto    schedule 08.03.2019
comment
Если обобщить причину этого утверждения, то это система планирования, которая у меня есть, которая использует это утверждение для создания таблицы календаря.   -  person Magno Alberto    schedule 08.03.2019
comment
Достаточно интересно, что в этом отчете об ошибке, о котором упоминал Билл, есть обходной путь, установив последовательность до максимального идентификатора перед вставкой новых записей. Ф.э. ALTER TABLE yourtable AUTO_INCREMENT=1;. И это как-то позволяет избежать пробелов. Странная ошибка/особенность, если вы спросите меня. Вероятно, это связано с разницей в буферизации между двигателями.   -  person LukStorms    schedule 08.03.2019
comment
MyISAM и InnoDB делают имеют различия в этой области. Также Galera, MySQL 8.0 и другие добавляют морщины в сжигание (или нет) id.   -  person Rick James    schedule 16.03.2019


Ответы (2)


Механизм автоинкремента необходим для создания уникальных значений, превышающих любое значение, сгенерированное ранее. Не гарантируется создание последовательных значений.

Здесь есть обсуждение по этому поводу: https://bugs.mysql.com/bug.php?id=57643

Точное создание последовательных значений не имеет большого значения, потому что любое значение может быть «потеряно» по другим причинам:

  • Ваш INSERT терпит неудачу, например, из-за нарушения ограничения, такого как UNIQUE KEY или FOREIGN KEY.
  • Вы откатываете транзакцию для своего INSERT.
  • Вы преуспеваете и фиксируете, но позже строка УДАЛЯЕТСЯ вами или другим сеансом.

Значения Auto-inc не возвращаются ни в какую очередь, потому что в это время другие одновременные сеансы могли сгенерировать дополнительные значения идентификатора. InnoDB не стоит поддерживать пул нераспределенных значений идентификаторов, потому что этот пул может стать огромным и расточительным.

Кроме того, может быть уместно «потерять» значение идентификатора, иначе кто-то может подумать, что строка, которую они хотели УДАЛИТЬ, каким-то образом вернулась.

person Bill Karwin    schedule 08.03.2019

Если обобщить причину этого утверждения, то это система планирования, которая у меня есть, которая использует это утверждение для создания таблицы календаря.

Не совсем в рамках вашего вопроса, который касался отсутствующих идентификаторов.
Но есть лучшие способы генерировать числа и / или таблицы календаря, чем повторять INSERT ... SELECT несколько раз.
Все подходы можно использовать напрямую, СОЕДИНЯЯ с другой таблицей или использовать для заполнения (индексируется) (временно). Таблица

Для генерации чисел.

Если ваша версия 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

Для 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

Для 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

person Raymond Nijland    schedule 08.03.2019
comment
Если вы используете MariaDB, просто используйте таблицу последовательности, такую ​​как seq_0_to_4096. - person Rick James; 16.03.2019
comment
Если вы используете MariaDB, просто используйте таблицу последовательности, такую ​​как seq_0_to_4096. Может быть опцией @RickJames Но механизм последовательности не включен по умолчанию во всех версиях MariaDB, что, я думаю, вы имели в виду с таблица последовательности, такая как seq_0_to_4096, она включена в MariaDB 10.1.. - person Raymond Nijland; 17.03.2019