У меня есть случай, когда я должен ограничить количество строк для каждого пользователя в таблице. Теперь я делаю это с помощью проверки COUNT * FROM table
перед вставкой, и если количество равно/больше разрешенного, я выдаю ошибку. Запрос COUNT и INSERT выполняется в одной транзакции. Но при 5000 онлайн-пользователях и 50 000 запросов в минуту у меня есть лишние записи (больше лимита) в таблице. Похоже на состояние гонки на параллельных вставках. Как я могу этого избежать? Может ли кто-нибудь предложить некоторые лучшие практики?
Параллельные вставки и состояние гонки в MySQL
Ответы (2)
Используйте отдельную таблицу, которая будет поддерживать пользователя и количество вставленных строк. Используйте идентификатор пользователя в качестве внешнего ключа к основной таблице. Теперь, если у вас есть приложение на основе сеанса, вы можете загружать данные в сеанс или память и продолжать извлекать их/обновлять счетчик после каждой вставки в сеанс/память и базу данных, а затем фактически вставлять в основную таблицу.
person
urs_ng
schedule
24.09.2018
В чем разница между вашим и моим текущим решением? Это почти то же самое, и есть вероятность состояния гонки между проверкой и вставкой.
- person LONGMAN; 25.09.2018
Опять же, вам придется заблокировать читаемые записи, чтобы включить контроль параллелизма. Преимущество такого решения может заключаться в том, что вам не нужно блокировать записи в таблице транзакций, а только в этой производной таблице.
- person Shadow; 25.09.2018
Проблема называется Фантомное чтение. Обычно это можно решить, используя уровень изоляции транзакции Serializable:
https://en.wikipedia.org/wiki/Isolation_(database_systems)
Но это может снизить производительность. Так что, если у вас много вставок, попробуйте и другие варианты из комментариев.
person
mroman
schedule
18.10.2018
SELECT COUNT(*)...
, а затемINSERT ...
есть два варианта: 1 перепишите SELECT и INSERT в один запрос, напримерINSERT INTO table (<columns>) SELECT (<columns|data what you want to insert>) FROM table WHERE .. [GROUP BY ...] [HAVING COUNT(*) < 100]
2 Используйте триггер INSERT BEFORE с SIGNAL. - person Raymond Nijland   schedule 24.09.2018INSERT INTO table (<columns>) SELECT (<columns|data what you want to insert>) FROM table WHERE 0
, обратите внимание наWHERE 0
, который также может работать с предложением HAVING сCOUNT(*) < 100
, если COUNT (*) больше, чем 100, если это то же самое, что и false или 0, что делает егоHAVING 0
, поэтому ничего не вставляется. - person Raymond Nijland   schedule 25.09.2018