Справочная информация. Я работаю над системой, в которой разработчики, похоже, используют функцию, которая выполняет запрос MYSQL, такой как "SELECT MAX(id) AS id FROM TABLE"
всякий раз, когда им нужно получить идентификатор последней вставленной строки (таблица с колонкой auto_increment).
Я знаю, что это ужасная практика (потому что одновременные запросы будут мешать записи), и я пытаюсь сообщить об этом нетехнической / управленческой команде, к которой их ответ …
"Oh okay, we'll only face this problem when we have (a) a lot of users, or (b) it'll only happen when two people try doing something at _exactly_ the same time"
Я не согласен ни с одной точкой, и думаю, что мы столкнемся с этой проблемой гораздо раньше, чем планируем. Тем не менее, я пытаюсь вычислить (или указать механизм), чтобы рассчитать, сколько пользователей должно использовать систему, прежде чем мы начнем видеть перепутанные ссылки.
Любая математическая информация об этом? Опять же, я ЗНАЮ его ужасную практику, я просто хочу понять переменные в этой ситуации …
Обновление: спасибо за комментарии людей – мы движемся в правильном направлении и исправляем код!
Дело не в том, что вероятные плохие ситуации вероятны. Дело в том, возможно ли это. Пока существует нетривиальная вероятность возникновения проблемы, если она известна, ее следует избегать.
Это не значит, что мы говорим об изменении вызова одной линии в монстра из 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.
Вместо того, чтобы использовать SELECT MAX(id)
вы можете сделать так, как говорится в документации :
Вместо этого используйте внутреннюю функцию MySQL SQL LAST_INSERT_ID () в SQL-запросе
Несмотря на это, ни SELECT MAX(id)
ни mysql_insert_id()
являются «потокобезопасными», и вы все еще можете иметь состояние гонки. Лучший вариант, который у вас есть, – заблокировать таблицы до и после ваших запросов. Или даже лучше использовать транзакции.
У меня нет математики для этого, но я бы отметил, что ответ (а) немного глуп. Разве компания не хочет много пользователей? Разве это не цель ? Этот ответ подразумевает, что они скорее разрешат проблему дважды, возможно, за большие деньги во второй раз, вместо того, чтобы решить ее правильно.
Это произойдет, когда кто-то добавит что-то в таблицу между одной вставкой и запущенным запросом. Поэтому, чтобы ответить на ваш вопрос, у двух человек, использующих систему, есть вероятность, что все пойдет не так.
По крайней мере, используя LAST_INSERT_ID (), вы получите последний идентификатор для определенного ресурса, поэтому не имеет значения, сколько новых записей было добавлено между ними.
Помимо риска получения неверного значения идентификатора, есть также дополнительные накладные запросы на базу данных SELECT MAX (id), и на самом деле это больше PHP-код, чем простой mysql_insert_id (). Почему сознательно кодировать что-то медленное?