Вставить в дубликат ключа - идентификатор приращения пропущен - PullRequest
0 голосов
/ 16 мая 2018

В настоящее время у меня есть сценарий выполнения SQL, который обновляет строку дубликата ключа, которая выглядит следующим образом.

    $stmt = $dbCon->prepare("INSERT INTO videos_rating (videos_rating_video_fk, "
            . " videos_rating_user_fk, "
            . " videos_rating_rating) "
            . " VALUES (:video_id, "
            . " :user_id, "
            . " :video_rating) "
            . " ON DUPLICATE KEY UPDATE videos_rating_rating = :video_rating");

Этот сценарий работает нормально, но есть способ предотвратить выход столбца с автоинкрементом изsync?

Предположим, что мы начинаем с пустой таблицы, затем я оцениваю видео, которое затем создает строку с идентификатором 1, затем пользователь снова выполняет SQL, оценивая то же видео ниже или ниже.более высокий рейтинг, и строка будет обновлена, потому что теперь она является дублирующим ключом, без проблем.

Проблема заключается в следующем.

В следующий раз, когда другой пользователь оценит новое новое видео, теперь начнется строкас идентификатором 3, а не 2?

Таблица будет выглядеть следующим образом

id | videos_rating_user_fk | videos_rating_rating
1  | 1                     | 4
3  | 2                     | 5

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

Я знаю, что идентификаторы не должны выглядеть «хорошо», но очень раздражает, что идентификаторы прыгают с 30 - 51 - 82 - 85 -89 и т. Д. И не возникнет ли проблема в какой-то момент, когда будет достигнуто максимальное число UNSIGNED big int?Я не говорю, что когда-нибудь поднимусь так высоко, но все же.

Ответы [ 4 ]

0 голосов
/ 09 августа 2019

Для подтверждения, ответ Пола Шпигеля помог мне решить проблему. У меня был какой-то SQL-запрос 'Upsert', который использовал ON DUPLICATE KEY UPDATE, чтобы определить, создавать ли новую строку или обновлять существующую. Там, где строки часто обновлялись, переходы в назначенных идентификаторах были большими.

«проблема» в том, что движок «зарезервирует» идентификатор, прежде чем узнает, является ли он дубликатом.

Я решил проблему, разбив код SQL на отдельные операторы INSERT и UPDATE. Я больше не вижу проблемы.

0 голосов
/ 16 мая 2018

Я предполагаю, что вы используете стандартный InnoDB движок.В этом случае «проблема» заключается в том, что движок «зарезервирует» идентификатор, прежде чем он узнает, является ли он дубликатом или нет.Как только идентификатор «зарезервирован», он не может быть освобожден, потому что другой поток (другой пользователь) может выполнить вставку в ту же таблицу в «то же самое время».Есть и другие способы получения пробелов в столбце AUTO_INCREMENT без удаления каких-либо строк.Один из них - откат транзакции.

Вы можете попытаться "сбросить" следующее значение AUTO_INCREMENT после каждой вставки с помощью

alter table videos_rating auto_increment = 1;

Но я не могу сказать, какие проблемы вы можете запуститьв выполнении этого заявления в работающей живой среде.И я не собираюсь это выяснять.

Обратите внимание, что обычно это не проблема, потому что таблицы, в которых вы запускаете IODKU statemts (обычно), не нуждаются в столбце AUTO_INCREMENT.Как писал Сид в своем ответе, вы можете просто отбросить столбец id и определить свой уникальный ключ как первичный ключ.

0 голосов
/ 25 мая 2018

Живи с «горением» ид.AUTO_INCREMENT гарантирует не допускать повторяющихся значений, не не предоставляет никаких других гарантий.

Существует еще 4 способа, при которых идентификаторы могут * сгореть :REPLACE, Multi-Master / Galera, IGNORE, DELETE и, возможно, еще.

IODKU быстро захватил идентификатор, прежде чем обнаружил, что оператор превратится в UPDATE и ему не нужен идентификатор,В противном случае это может быть значительным ударом по производительности.

0 голосов
/ 16 мая 2018

Предположим, что ваша таблица построена следующим образом:

videos_rating_video_fk | videos_rating_user_fk | videos_rating_rating
-----------------------+-----------------------+----------------------

Первый ключ videos_rating_video_fk должен быть внешним ключом, а не первичным ключом с автоинкрементом.

Если пользователи 1 и2 проголосуйте за видео, которое имеет id 1, ваша таблица должна выглядеть следующим образом:

videos_rating_video_fk | videos_rating_user_fk | videos_rating_rating
-----------------------+-----------------------+----------------------
1                      | 1                     | 4
1                      | 2                     | 5

Для таблицы такого типа первичным ключом должен быть комбинация обоих внешних ключей и будет уникальной.Пользователь может проголосовать только один раз за видео (уникальный голос = уникальный ключ).За видео могут голосовать несколько пользователей, а пользователи могут голосовать за несколько видео.

Я предлагаю вам взглянуть на метод Merise для построения таблиц с ограничениями целостности и создания первичных ключей.

...