Устранение неполадок с запросами, которые, кажется, никогда не заканчиваются в SQL Server
В этой статье описаны действия по устранению неполадок, из-за которых запрос, который, кажется, никогда не завершается, или его завершение может занять много часов или дней.
Что такое бесконечный запрос?
В этом документе основное внимание уделяется запросам, которые продолжают выполняться или компилироваться, то есть их ЦП продолжает увеличиваться. Он не применяется к запросам, которые заблокированы или ожидают на каком-либо ресурсе, который никогда не освобождается (ЦП остается постоянным или изменяется очень мало).
Важно!
Если запросу осталось завершить выполнение, он в конечном итоге завершится. Это может занять всего несколько секунд, или может занять несколько дней.
Термин "бесконечный" используется для описания восприятия того, что запрос не завершается, когда на самом деле запрос в конечном итоге завершается.
Определение бесконечного запроса
Чтобы определить, выполняется ли запрос постоянно или зависает на узком месте, выполните следующие действия.
Выполните следующий запрос:
DECLARE @cntr int = 0 WHILE (@cntr < 3) BEGIN SELECT TOP 10 s.session_id, r.status, r.wait_time, r.wait_type, r.wait_resource, r.cpu_time, r.logical_reads, r.reads, r.writes, r.total_elapsed_time / (1000 * 60) 'Elaps M', SUBSTRING(st.TEXT, (r.statement_start_offset / 2) + 1, ((CASE r.statement_end_offset WHEN -1 THEN DATALENGTH(st.TEXT) ELSE r.statement_end_offset END - r.statement_start_offset) / 2) + 1) AS statement_text, COALESCE(QUOTENAME(DB_NAME(st.dbid)) + N'.' + QUOTENAME(OBJECT_SCHEMA_NAME(st.objectid, st.dbid)) + N'.' + QUOTENAME(OBJECT_NAME(st.objectid, st.dbid)), '') AS command_text, r.command, s.login_name, s.host_name, s.program_name, s.last_request_end_time, s.login_time, r.open_transaction_count, atrn.name as transaction_name, atrn.transaction_id, atrn.transaction_state FROM sys.dm_exec_sessions AS s JOIN sys.dm_exec_requests AS r ON r.session_id = s.session_id CROSS APPLY sys.Dm_exec_sql_text(r.sql_handle) AS st LEFT JOIN (sys.dm_tran_session_transactions AS stran JOIN sys.dm_tran_active_transactions AS atrn ON stran.transaction_id = atrn.transaction_id) ON stran.session_id =s.session_id WHERE r.session_id != @@SPID ORDER BY r.cpu_time DESC SET @cntr = @cntr + 1 WAITFOR DELAY '00:00:05' END
Проверьте пример выходных данных.
Действия по устранению неполадок, описанные в этой статье, особенно применимы, если вы заметили выходные данные, аналогичные приведенному ниже, когда загрузка ЦП увеличивается пропорционально затраченному времени без значительного времени ожидания. Важно отметить, что изменения в
logical_reads
этом случае не имеют значения, так как некоторые запросы T-SQL, привязанные к ЦП, могут вообще не выполнять никаких логических операций чтения (например, выполнение вычисленийWHILE
или цикл).session_id status cpu_time logical_reads wait_time wait_type 56 Запущена 7038 101000 0 NULL 56 готово к запуску 12040 301000 0 NULL 56 Запущена 17020 523000 0 NULL Эта статья неприменима, если вы наблюдаете сценарий ожидания, аналогичный приведенному ниже, когда ЦП не изменяется или изменяется незначительно, а сеанс ожидает ресурса.
session_id status cpu_time logical_reads wait_time wait_type 56 suspended 0 3 8312 LCK_M_U 56 suspended 0 3 13318 LCK_M_U 56 suspended 0 5 18331 LCK_M_U
Дополнительные сведения см. в разделе Диагностика ожиданий или узких мест.
Длительное время компиляции
В редких случаях вы можете наблюдать, что ЦП постоянно увеличивается с течением времени, но это не зависит от выполнения запроса. Вместо этого она может быть вызвана слишком длинной компиляцией (синтаксический анализ и компиляция запроса). В таких случаях проверка выходной столбец transaction_name и найдите значение sqlsource_transform
. Это имя транзакции указывает на компиляцию.
Сбор диагностических данных
- SQL Server 2008 г. — SQL Server 2014 г. (до sp2)
- SQL Server 2014 (после пакета обновления 2 (SP2) и SQL Server 2016 (до SP1)
- SQL Server 2016 г. (после sp1) и SQL Server 2017 г.
- SQL Server 2019 и более поздних версиях
Чтобы собрать диагностические данные с помощью SQL Server Management Studio (SSMS), выполните следующие действия.
Запишите XML-файл предполагаемого плана выполнения запроса .
Просмотрите план запроса, чтобы узнать, есть ли очевидные признаки того, откуда может возникнуть задержка. Типичные примеры:
- Сканирование таблиц или индексов (просмотрите предполагаемые строки).
- Вложенные циклы, управляемые огромным набором данных внешней таблицы.
- Вложенные циклы с большой ветвью во внутренней части цикла.
- Очереди таблиц.
- Функции в списке
SELECT
, обработка каждой строки которых занимает много времени.
Если запрос выполняется быстро в любое время, можно записать "быстрые" выполнения Фактический план выполнения XML для сравнения.
Метод проверки собранных планов
В этом разделе показано, как просмотреть собранные данные. Он будет использовать несколько планов ЗАПРОСОВ XML (с расширением *.sqlplan), собранных в SQL Server 2016 с пакетом обновления 1 (SP1) и более поздних сборках и версиях.
Чтобы сравнить планы выполнения, выполните следующие действия.
Откройте ранее сохраненный файл плана выполнения запроса (.sqlplan).
Щелкните правой кнопкой мыши пустую область плана выполнения и выберите Сравнить план выполнения.
Выберите второй файл плана запроса, который требуется сравнить.
Найдите толстые стрелки, указывающие на большое количество строк, передаваемых между операторами. Затем выберите оператор до или после стрелки и сравните количество фактических строк в двух планах.
Сравните второй и третий планы, чтобы узнать, происходит ли наибольший поток строк в одних и том же операторах.
Пример:
Разрешение
Убедитесь, что статистика обновлена для таблиц, используемых в запросе.
Найдите отсутствующие рекомендации по индексу в плане запроса и примените ее.
Перепишите запрос, чтобы упростить его:
- Используйте более селективные
WHERE
предикаты, чтобы сократить объем обрабатываемых данных. - Разорвать его на части.
- Выберите некоторые части во временные таблицы и соедините их позже.
- Удалите
TOP
,EXISTS
иFAST
(T-SQL) в запросах, которые выполняются в течение очень длительного времени из-за цели строки оптимизатора. Кроме того, можно использовать подсказкуDISABLE_OPTIMIZER_ROWGOAL
. Дополнительные сведения см. в разделе Row Goals Gone Rogue. - Избегайте использования общих табличных выражений (CTE) в таких случаях, когда они объединяют инструкции в один большой запрос.
- Используйте более селективные
Попробуйте использовать указания запросов , чтобы создать лучший план:
HASH JOIN
илиMERGE JOIN
подсказкаFORCE ORDER
ПодсказкаFORCESEEK
ПодсказкаRECOMPILE
- ИСПОЛЬЗУЙТЕ
PLAN N'<xml_plan>'
, если у вас есть быстрый план запроса, который можно принудительно применить.
Используйте хранилище запросов (QDS) для принудительного применения хорошо известного плана, если такой план существует и если версия SQL Server поддерживает хранилище запросов.
Диагностика ожиданий или узких мест
Этот раздел включен в качестве справки на случай, если проблема не является длительным запросом на управление ЦП. Его можно использовать для устранения неполадок с запросами, которые выполняются долго из-за ожиданий.
Чтобы оптимизировать запрос, ожидающий узких мест, определите, сколько времени ожидания и где находится узкое место (тип ожидания). После подтверждения типа ожидания сократите время ожидания или полностью исключите его.
Чтобы вычислить приблизительное время ожидания, вычесть время ЦП (время рабочей роли) из затраченного времени запроса. Как правило, время ЦП — это фактическое время выполнения, а оставшаяся часть времени существования запроса ожидается.
Примеры вычисления приблизительной продолжительности ожидания:
Затраченное время (мс) | Время ЦП (мс) | Время ожидания (мс) |
---|---|---|
3200 | 3000 | 200 |
7080 | 1000 | 6080 |
Определение узкого места или ожидания
Чтобы определить исторические запросы с длительным ожиданием (например, >20 % от общего затраченного времени составляет время ожидания), выполните следующий запрос. Этот запрос использует статистику производительности для кэшированных планов запросов с начала SQL Server.
SELECT t.text, qs.total_elapsed_time / qs.execution_count AS avg_elapsed_time, qs.total_worker_time / qs.execution_count AS avg_cpu_time, (qs.total_elapsed_time - qs.total_worker_time) / qs.execution_count AS avg_wait_time, qs.total_logical_reads / qs.execution_count AS avg_logical_reads, qs.total_logical_writes / qs.execution_count AS avg_writes, qs.total_elapsed_time AS cumulative_elapsed_time FROM sys.dm_exec_query_stats qs CROSS apply sys.Dm_exec_sql_text (sql_handle) t WHERE (qs.total_elapsed_time - qs.total_worker_time) / qs.total_elapsed_time > 0.2 ORDER BY qs.total_elapsed_time / qs.execution_count DESC
Чтобы определить выполняемые в настоящее время запросы с ожиданиями более 500 мс, выполните следующий запрос:
SELECT r.session_id, r.wait_type, r.wait_time AS wait_time_ms FROM sys.dm_exec_requests r JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id WHERE wait_time > 500 AND is_user_process = 1
Если вы можете собрать план запроса, проверка WaitStats из свойств плана выполнения в SSMS:
- Выполните запрос с включением фактического плана выполнения в.
- Щелкните правой кнопкой мыши левый оператор на вкладке План выполнения .
- Выберите Свойства , а затем — Свойство WaitStats .
- Проверьте Значения WaitTimeMs и WaitType.
Если вы знакомы со сценариями PSSDiag/SQLdiag или SQL LogScout LightPerf/GeneralPerf, рассмотрите возможность использования любого из них для сбора статистики производительности и определения ожидающих запросов на экземпляре SQL Server. Вы можете импортировать собранные файлы данных и анализировать данные о производительности с помощью SQL Nexus.
Ссылки для устранения или сокращения ожиданий
Причины и способы их устранения для каждого типа ожидания различаются. Не существует единого общего метода для разрешения всех типов ожидания. Ниже приведены статьи по устранению неполадок и устранению распространенных проблем с типом ожидания:
- Общие сведения и устранение проблем с блокировкой (LCK_M_*)
- Общие сведения и устранение проблем с блокировкой базы данных Azure SQL
- Устранение неполадок с низкой производительностью SQL Server, вызванной проблемами ввода-вывода (PAGEIOLATCH_*, WRITELOG, IO_COMPLETION, BACKUPIO)
- Разрешение конфликтов по вставке последней страницы PAGELATCH_EX в SQL Server
- Объяснения и решения, предоставляемые памятью (RESOURCE_SEMAPHORE)
- Устранение неполадок с медленными запросами, возникающими в результате ASYNC_NETWORK_IO типа ожидания
- Устранение неполадок с типом ожидания высокого HADR_SYNC_COMMIT в группах доступности Always On
- Как это работает: CMEMTHREAD и отладка
- Обеспечение того, чтобы параллелизм ждал действия (CXPACKET и CXCONSUMER)
- ОЖИДАНИЕ THREADPOOL
Описание многих типов ожиданий и то, что они указывают, см. в таблице Типы ожиданий.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по