Практика SQL Server

Таймауты SQL Server: отмена и безопасный повтор

Разделяйте таймауты соединения, команды и блокировок, корректно завершайте транзакции и исключайте повторные записи после потери ответа.

Таймаут сообщает, что вызывающая сторона исчерпала свой срок ожидания. Сам по себе он не объясняет, был ли SQL медленным, заблокированным, отмененным до фиксации или успешно зафиксированным до потери ответа. Немедленный повтор с предположением об откате может превратить задержку в дублирование бизнес-операций.

Определить, какой срок истек

Таймаут соединения относится к его открытию, включая сеть, аутентификацию и получение ресурсов. Таймаут команды относится к выполнению через клиентский драйвер. SET LOCK_TIMEOUT ограничивает ожидание блокировок внутри SQL Server. Это разные этапы, и настройки не заменяют друг друга.

Пример меняет только срок ожидания блокировки текущей сессии и затем восстанавливает неограниченное значение. Общая длительность запроса этим не ограничивается.

SET LOCK_TIMEOUT 1500;
SELECT @@LOCK_TIMEOUT AS LockTimeoutMilliseconds;
SET LOCK_TIMEOUT -1;

SELECT XACT_STATE() AS TransactionState,
       @@TRANCOUNT AS TransactionCount;

Таймаут блокировки дает классифицируемую ошибку SQL Server. Таймаут команды обычно сообщает драйвер, отправляя запрос на отмену. Записывайте драйвер, подробности ошибки, длительность, идентификатор корреляции и наличие активной транзакции. Общего сообщения веб-фреймворка недостаточно для установления причины.

Также отделяйте срок HTTP-запроса от бюджета команды базы данных. Если HTTP-слой прекращает ожидание, но приложение не передает отмену, SQL может продолжать работу. Согласуйте сроки и оставьте время на очистку состояния и понятный ответ.

Наблюдать запрос до его исчезновения

Во время инцидента сохраняйте ожидания, блокирующие сессии, время и открытые транзакции. Эти запросы только читают состояние, но требуют диагностических прав для соответствующей версии.

SELECT
    session_id, request_id, status, command,
    wait_type, wait_time, blocking_session_id,
    total_elapsed_time, cpu_time,
    reads, logical_reads, writes
FROM sys.dm_exec_requests
WHERE session_id <> @@SPID;

SELECT
    session_id, status, open_transaction_count,
    last_request_start_time, last_request_end_time,
    host_name, program_name
FROM sys.dm_exec_sessions
WHERE is_user_process = 1
  AND open_transaction_count > 0;

Ожидание блокировки требует другого исследования, чем рост CPU или ожидание рабочей памяти. Второй запрос позволяет увидеть спящую сессию с открытой транзакцией, которой может не быть в списке активных запросов. Имена машины и программы передаются клиентом и служат диагностическими метками, а не надежной идентификацией безопасности.

Для повторяющихся случаев сопоставляйте время приложения с целевой сессией Extended Events, включающей attention и подходящие события завершения или ошибки. Attention подтверждает просьбу клиента остановить работу. Он не доказывает, что причиной была ручная отмена, истечение срока или проблема самого клиента.

Отмена не гарантирует откат всех явных транзакций. Приложение должно управлять жизненным циклом собственных транзакций. После ошибки по возможности откатите свою транзакцию, обработайте сбой очистки и закройте соединение, пригодность которого не удается установить. Не полагайтесь только на SQL CATCH: клиентский attention обрабатывается не как любая обычная ошибка T-SQL.

При этом библиотечный код не должен без договоренности откатывать транзакцию внешнего вызывающего компонента. Контракт обязан определять, кто начинает, фиксирует и прекращает работу. Эта граница ответственности не менее важна, чем выбранное количество секунд.

Повторять операцию с постоянной идентичностью

Представьте похожую на платеж команду, которая успела зафиксироваться, но потеряла ответ. Повтор с новым идентификатором может создать ту же операцию второй раз. Назначьте бизнес-команде стабильный ключ идемпотентности и обеспечьте его уникальность в базе. Храните результат, достаточный для ответа при повторной отправке ключа.

Запись дедупликации и бизнес-изменение должны фиксироваться вместе. Отдельные транзакции позволяют сохранить ключ без выполнения операции. Если тот же ключ приходит с другим содержимым, отклоните несоответствие, а не возвращайте чужой по смыслу результат.

Используйте ограниченные повторы с задержкой только для ошибок, которые контракт разрешает повторять. Дополнительные запросы не устраняют длинную цепочку блокировок. Неизвестный результат commit требует проверки существующего исхода. Протестируйте отмену во время исполнения, при блокировке и потерю ответа после фиксации.

Для намеренно долгой выгрузки увеличение таймаута может быть оправданно. Но измерьте удерживаемые ресурсы и влияние на интерактивные запросы. В журнале результата отдельно отмечайте бизнес-успех и доставку ответа: это разные события. Такая детализация помогает поддержке объяснить пользователю, прошла ли операция, даже когда интерфейс сообщил об истечении времени.

Техническая документация: Microsoft Learn: Query timeout troubleshooting · Microsoft Learn: SET LOCK_TIMEOUT · Microsoft Learn: XACT_STATE.

Вопрос по статье

Есть вопрос по этой теме?

Расскажите, что вы оцениваете или с какой проблемой столкнулись. Мы ответим с практической рекомендацией.

Inquiries are not enabled in this preview.

Задать вопрос по этой статье