@immelnikoff
Изучаю БД

Почему в MySQL 8.0 при последовательной записи через пользовательскую функцию в автоинкрементном id образуются пропуски?

Есть функция, через которую приложение пишет в базу на сервере MySQL 8.0:
CREATE function `insert_photo` (_link char(36), _material_id mediumint unsigned, _img mediumtext) returns mediumint unsigned
BEGIN
declare _id mediumint unsigned;
declare l binary(16);
set l = UNHEX(replace(_link, '-', ''));
insert ignore into Photo(link, material_id, img) value(l, _material_id, from_base64(_img));
select id into _id from Photo where link = l;
return _id;
END

Функция принимает данные для записи в базу и возвращает автоинкрементный id сделанной записи. Приложение пишет последовательно, то есть функция для следующей записи не вызывается пока не будет получен id предыдущей записи. Проблема в следующем. Я заметил, что в таблице в автоинкрементном id есть немало пропусков – при 10 000 записей id увеличивается на 15 000. Вообще не понятно откуда в данном случае могут взяться пропуски. Стал смотреть детальнее и обнаружил, что примерно для половины передаваемых данных функция вызывалась дважды. Для условных 10 000 единиц данных 5 000 из них были записаны при первом вызове функции, остальные 5 000 – только со второй попытки. Я сначала подумал, что по каким-то причинам возвращаемый функцией id не доходит до приложения (сбои в сети) и приложение повторно передает эти данные функции и получает id со второго раза. Но тут есть сразу два возражения. Во-первых, связь между сервером MySQL 8.0 и приложением надежная, которая в принципе не может давать таких сбоев. А, во-вторых, в базе нет ни одной записи, которая была бы сделана с 3-й или большей попытки. Прям магия какая-то! Кто-нибудь может прояснить причину подобного поведения MySQL 8.0?
  • Вопрос задан
  • 98 просмотров
Пригласить эксперта
Ответы на вопрос 2
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
MySQL выделяет блок следующих ID до начала выполнения запроса, основываясь на максимальном количестве вставляемых запросом строк.
Если какие-то строки не вставились (INSERT IGNORE, ошибка при вставке и т.п.), то выделенные ID обратно не возвращаются, поскольку за это время следующие за ними ID могли быть выделены следующим запросам.
Ответ написан
Melkij
@Melkij
PostgreSQL DBA
А зачем эти извращения? Есть гарантированно конкурентно-безопасный LAST_INSERT_ID()

У вас insert ignore используется. Значит, данные натыкаются на уникальные индексы? auto_increment при этом штатно тикает.
Вообще auto_increment - это гарантированная уникальность. Если вы хотите "без пропусков" - вы взяли не тот инструмент.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы