Программное обеспечение: Django 2.1.0, Python 3.7.1, MariaDB 10.3.8, Linux Ubuntu 18LTS
Недавно мы добавили некоторую нагрузку в новое приложение и начали наблюдать множество взаимоблокировок.После долгих поисков я обнаружил, что запрос Django select_for_update привел к SQL с несколькими подзапросами (3 или 4).Во всех тупиках, которые я видел до сих пор, по крайней мере одна из транзакций включает в себя этот SQL с несколькими подзапросами.
мой вопрос ... Блокирует ли select_for_udpate записи из каждой задействованной таблицы? В моем случае блокируются ли записи из основного SELECT и из других таблиц, используемых подзапросами?Или только записи из основного SELECT?
Из документов Django:
По умолчанию select_for_update () блокирует все строки, выбранные запросом.Например, строки связанных объектов, указанных в select_related (), блокируются в дополнение к строкам модели набора запросов.
Однако я не использую select_related (), по крайней мере, я не выражаю его явно.
Резюме моего приложения:
with transaction.atomic():
ModelName.objects.select_for_update().filter(...)
...
update record that is locked
...
- 50+ клиентов, отправляющих запросы к базе данных одновременно
- Некоторые из этих запросов запрашивают одну и ту же запись.Это означает, что разные транзакции будут запускать один и тот же SQL в одно и то же время.
После долгих чтений я попытался установить тупик под контролем:
1 - Попробуйте/ Перехват ошибки исключения «1213» (взаимоблокировка).Когда это произойдет, подождите 30 секунд и повторите запрос.Здесь я полагаюсь на функцию ROLLBACK от движка базы данных.Кроме того, распечатайте выходные данные SHOW ENGINE INNODB STATUS и SHOW PROCESSLIST.Но SHOW PROCESSLIST не дает полезной информации.
2 - Измените Django select_on_update, чтобы он не создавал SQL с подзапросами.Теперь сгенерированный SQL содержит один WHERE со значениями и без подзапросов.
Что еще можно сделать, чтобы уменьшить тупики?