Как плохо использовать SELECT MAX (id) в MYSQL вместо mysql_insert_id () в PHP?

Справочная информация: я работаю в системе, в которой разработчики, похоже, используют функцию, которая выполняет запрос MYSQL, например " ВЫБЕРИТЕ МАКС (id) КАК ID ИЗ ТАБЛИЦЫ " (а) много пользователей, или (б) это случится только тогда, когда два человека попытаются что-то сделать в то же время

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

Есть ли математическое понимание этого? Опять же, я ЗНАЮ, что это ужасная практика, я просто хочу понять переменные в этой ситуации ...


Обновление: Спасибо за комментарии, друзья - мы движемся в правильном направлении и исправляем код!

12
задан DrMHC 19 August 2010 в 09:53
поделиться

5 ответов

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

Это не похоже на то, что мы говорим об изменении вызова однострочной функции на 5000-строчного монстра, чтобы справиться с удаленно возможным крайним случаем. Мы говорим о сокращении вызова до более удобочитаемого и более правильного использования.

Я согласен с @Mark Baker в том, что есть некоторые соображения по поводу производительности, но поскольку id является первичным ключом, запрос MAX будет очень быстрым. Конечно, LAST_INSERT_ID () будет быстрее (поскольку он просто читает из переменной сеанса), но только на незначительную величину.

И для этого не нужно много пользователей. Все, что вам нужно, - это много одновременных запросов (даже не так много). Если время между началом вставки и началом выбора составляет 50 миллисекунд (при условии, что движок БД безопасен для транзакций), то вам нужно всего 20 запросов в секунду, чтобы начать последовательно решать проблему с этим. Дело в том, что окно для ошибки нетривиально. Если вы скажете 20 запросов в секунду (что на самом деле немного) и предположите, что в среднем человек посещает одну страницу в минуту, вы говорите только о 1200 пользователях. И это для того, чтобы это происходило регулярно. Это могло случиться один раз только с двумя пользователями.

И прямо из документации MySQL по теме :

You can generate sequences without calling LAST_INSERT_ID(), but the utility of 
using the function this way is that the ID value is maintained in the server as 
the last automatically generated value. It is multi-user safe because multiple 
clients can issue the UPDATE statement and get their own sequence value with the
SELECT statement (or mysql_insert_id()), without affecting or being affected by 
other clients that generate their own sequence values.
5
ответ дан 2 December 2019 в 23:19
поделиться

У меня нет математики для этого, но я хотел бы отметить, что ответ (а) немного глупый. Разве компании не нужно много пользователей? Разве это не цель ? Этот ответ подразумевает, что они предпочтут решить проблему дважды, возможно, с большими затратами во второй раз, вместо того, чтобы решить ее один раз правильно в первый раз.

0
ответ дан 2 December 2019 в 23:19
поделиться

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

По крайней мере, использование LAST_INSERT_ID () позволит получить последний идентификатор для конкретного ресурса, поэтому не имеет значения, сколько новых записей было добавлено между ними.

0
ответ дан 2 December 2019 в 23:19
поделиться

В дополнение к риску получить неправильное значение идентификатора, есть также дополнительные накладные расходы на запрос базы данных SELECT MAX (id), и это больше кода PHP для фактического выполнения, чем простой mysql_insert_id ( ). Зачем специально кодировать что-то, чтобы замедлить работу?

0
ответ дан 2 December 2019 в 23:19
поделиться

Вместо использования SELECT MAX (id) вы должны сделать, как сказано в документации :

Вместо этого используйте внутреннюю функцию MySQL SQL LAST_INSERT_ID () в запросе SQL

Даже в этом случае ни SELECT MAX (id) , ни mysql_insert_id () не являются «поточно-ориентированными», и вы все равно можете иметь состояние гонки. Лучший вариант - заблокировать таблицы до и после ваших запросов. А еще лучше использовать транзакции.

1
ответ дан 2 December 2019 в 23:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: