Справочная информация: я работаю в системе, в которой разработчики, похоже, используют функцию, которая выполняет запрос MYSQL, например " ВЫБЕРИТЕ МАКС (id) КАК ID ИЗ ТАБЛИЦЫ "
(а) много пользователей, или
(б) это случится только тогда, когда два человека попытаются что-то сделать
в то же время
Я не согласен ни с одним из этих пунктов и думаю, что мы столкнемся с этой проблемой гораздо раньше, чем планируем. Тем не менее, я пытаюсь вычислить (или изобразить механизм), чтобы подсчитать, сколько пользователей должно использовать систему, прежде чем мы начнем видеть испорченные ссылки.
Есть ли математическое понимание этого? Опять же, я ЗНАЮ, что это ужасная практика, я просто хочу понять переменные в этой ситуации ...
Обновление: Спасибо за комментарии, друзья - мы движемся в правильном направлении и исправляем код!
Дело не в том, вероятны ли потенциально плохие ситуации.Дело в том, возможны ли они. Пока существует нетривиальная вероятность возникновения проблемы, если она известна, ее следует избегать.
Это не похоже на то, что мы говорим об изменении вызова однострочной функции на 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.
У меня нет математики для этого, но я хотел бы отметить, что ответ (а) немного глупый. Разве компании не нужно много пользователей? Разве это не цель ? Этот ответ подразумевает, что они предпочтут решить проблему дважды, возможно, с большими затратами во второй раз, вместо того, чтобы решить ее один раз правильно в первый раз.
Это произойдет, если кто-то что-то добавил в таблицу между одной вставкой и выполнением этого запроса. Итак, отвечая на ваш вопрос, два человека, использующие систему, могут что-то пойти не так.
По крайней мере, использование LAST_INSERT_ID () позволит получить последний идентификатор для конкретного ресурса, поэтому не имеет значения, сколько новых записей было добавлено между ними.
В дополнение к риску получить неправильное значение идентификатора, есть также дополнительные накладные расходы на запрос базы данных SELECT MAX (id), и это больше кода PHP для фактического выполнения, чем простой mysql_insert_id ( ). Зачем специально кодировать что-то, чтобы замедлить работу?
Вместо использования SELECT MAX (id)
вы должны сделать, как сказано в документации :
Вместо этого используйте внутреннюю функцию MySQL SQL LAST_INSERT_ID () в запросе SQL
Даже в этом случае ни SELECT MAX (id)
, ни mysql_insert_id ()
не являются «поточно-ориентированными», и вы все равно можете иметь состояние гонки. Лучший вариант - заблокировать таблицы до и после ваших запросов. А еще лучше использовать транзакции.