Если одна транзакция долго остаётся открытой, она продолжает держать блокировки, а БД не может очистить (purge) старые версии данных, и всё постепенно замедляется.
Почему Транзакция остаётся открытой, пока ждёт ответа другого сервера, или на основной БД в рабочее время идёт долгий агрегирующий запрос → Следствие Захваченные блокировки не освобождаются, старые версии данных, которые нужно удалить, продолжают копиться → На экране Таймауты в функциях, которые обращаются к этой строке, за несколько часов в целом замедляются сохранения и чтение данных
Основной ответственный Команда разработки · Разработка сервера · Совместно Команда инфраструктуры · Инфраструктура БД
Команда разработки: задачи
Не ждать внутри транзакции сетевых вызовов и ввода пользователя, агрегирующие запросы выполнять на реплике.
Команда инфраструктуры: задачи
Настроить алерт на долго открытые транзакции и принудительно их завершать, выделить реплику для агрегации, следить за ростом undo-лога и мёртвых строк.
На графике
Плавный рост · длина undo-лога (History list length), число мёртвых строк
Где смотреть
В MySQL искать самую старую транзакцию по trx_started в INFORMATION_SCHEMA.INNODB_TRX и смотреть History list length (объём ещё не очищенного undo-лога) в секции TRANSACTIONS вывода SHOW ENGINE INNODB STATUS. В PostgreSQL смотреть xact_start в pg_stat_activity и сессии в состоянии idle in transaction, а также n_dead_tup в pg_stat_user_tables
Подтверждает
Есть транзакция возрастом от нескольких минут до нескольких часов, всё это время History list length или n_dead_tup растут, а после завершения этой транзакции очистка (purge, VACUUM) их снижает
Опровергает
Если старых транзакций нет, а в целом всё медленно, дело в контрольных точках (db-checkpoint) или в диске
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)
Подробнее
Чтобы читающие видели данные в состоянии до изменения, БД хранит старые версии (MVCC). Удалить эти записи можно только после завершения самой старой транзакции, поэтому если одна транзакция открыта несколько часов, в MySQL копится undo-лог, а в PostgreSQL мёртвые строки (dead tuple), которые не может убрать VACUUM. В SQL Server журнал транзакций не сокращается и может заполнить диск.
Источники
InnoDB Multi-VersioningMySQL Пока остаётся транзакция, которой могут понадобиться старые версии, update undo-лог нельзя удалить и rollback-сегмент растёт. Рекомендуется часто коммитить даже транзакции, которые только читают
Routine Vacuuming (PostgreSQL Documentation)PostgreSQL Старые версии строк нельзя удалить, пока их может видеть другая транзакция, долго открытую транзакцию нужно завершить или закрыть её сессию
Purge ConfigurationMySQL Purge очищает список undo-логов закоммиченных транзакций (history list), отставание показывает History list length в секции TRANSACTIONS вывода SHOW ENGINE INNODB STATUS