Когда ранее быстрый SQL-запрос начинает работать медленно, где я могу найти источник проблемы?


37

Задний план

У меня есть запрос к SQL Server 2008 R2, который объединяет и / или объединяет влево около 12 различных «таблиц». База данных довольно большая, со многими таблицами более 50 миллионов строк и около 300 различных таблиц. Это для крупной компании, которая имеет 10 складов по всей стране. Все склады читают и пишут в базу данных. Так что он довольно большой и довольно занятый.

Запрос, с которым у меня возникли проблемы, выглядит примерно так:

select t1.something, t2.something, etc.
from Table1 t1
    inner join Table2 t2 on t1.id = t2.t1id
    left outer join (select * from table 3) t3 on t3.t1id = t1.t1id
    [etc]...
where t1.something = 123

Обратите внимание, что одно из объединений находится на некоррелированном подзапросе.

Проблема в том, что начиная с этого утра, без каких-либо изменений (о которых я или кто-либо из моей команды знаю) в системе, запрос, который обычно занимает около 2 минут, начинает работать полтора часа - когда он побежал на всех. Остальная часть базы данных гудит просто отлично. Я взял этот запрос из sproc, в котором он обычно выполняется, и запустил его в SSMS с жестко запрограммированными переменными параметров с той же медлительностью.

Странность заключается в том, что когда я беру некоррелированный подзапрос и бросаю его во временную таблицу, а затем использую его вместо подзапроса, запрос выполняется нормально. Также (и это самое странное для меня), если я добавлю этот фрагмент кода в конец запроса, запрос будет работать отлично:

and t.name like '%'

Из этих небольших экспериментов я сделал вывод (возможно, неверно), что причина замедления заключается в том, как настроен кэшированный план выполнения SQL - когда запрос немного отличается, он должен создать новый план выполнения.

Мой вопрос заключается в следующем: когда запрос, который раньше выполнялся быстро, внезапно начинает выполняться медленно среди ночи, и ничто другое не затрагивается, за исключением этого одного запроса, как мне устранить его и как предотвратить его в будущем ? Как мне узнать, что SQL делает внутренне, чтобы сделать его таким медленным (если бы некорректный запрос выполнялся, я мог бы получить план его выполнения, но он не запустится - может быть, ожидаемый план выполнения мне что-нибудь даст?)? Если эта проблема связана с планом выполнения, как мне не допустить, чтобы SQL думал, что действительно дурацкие планы выполнения - это хорошая идея?

Кроме того, это не проблема с анализом параметров. Я видел это раньше, и это не так, потому что даже когда я жестко программирую переменные в SSMS, я все равно получаю низкую производительность.


Не могли бы вы поделиться планом запроса (медленным) здесь: brentozar.com/pastetheplan
MJH

Ответы:


32

Когда запрос, который раньше выполнялся быстро, внезапно начинает выполняться медленно среди ночи, и ничто другое не затрагивается, кроме этого одного запроса, как мне устранить его ...?

Вы можете начать с проверки, находится ли план выполнения в кэше. Проверьте sys.dm_exec_query_stats, sys.dm_exec_procedure_statsи sys.dm_exec_cached_plans. Если неверный план выполнения все еще кэшируется, вы можете проанализировать его и проверить статистику выполнения. Статистика выполнения будет содержать информацию в виде логических чтений, времени процессора и времени выполнения. Это может дать четкие указания о том, в чем заключается проблема (например, большое сканирование или блокировка). См. Идентификация проблемных запросов для объяснения, как интерпретировать данные.

Кроме того, это не проблема с анализом параметров. Я видел это раньше, и это не так, потому что даже когда я жестко программирую переменные в SSMS, я все равно получаю низкую производительность.

Я не убежден. Жесткое кодирование переменных в SSMS не доказывает, что прошлый неверный план выполнения не был скомпилирован с искаженным вводом. Пожалуйста, прочитайте Параметры Sniffing, Embedding и RECOMPILE Options для очень хорошей статьи на эту тему. Медленно в приложении, быстро в SSMS? Понимание загадок производительности - еще одна отличная ссылка.

Из этих небольших экспериментов я сделал вывод (возможно, неверно), что причина замедления заключается в том, как настроен кэшированный план выполнения SQL - когда запрос немного отличается, он должен создать новый план выполнения.

Это можно легко проверить. SET STATISTICS TIME ONпокажет вам время компиляции и выполнения. SQL Server: статистические счетчики производительности также покажут, является ли проблема компиляции (честно говоря, я нахожу это маловероятным).

Однако есть нечто похожее, что вы можете поразить: ворота предоставления запроса. Прочитайте раздел Понимание предоставления памяти SQL-серверу для получения подробной информации Если ваш запрос запрашивает большой грант в тот момент, когда нет доступной памяти, ему придется подождать, и все это будет выглядеть как «медленное выполнение» для приложения. Анализ статистики ожидания покажет, если это так.

Для более общего обсуждения того, что измерять и что искать, см. Как анализировать производительность SQL Server.


7

Это проблема выполнения сложных запросов в SQL Server. К счастью, это случается не так часто.

Посмотрите на план запроса для запроса (когда он работает медленно). Я предполагаю, что вы найдете объединение с вложенным циклом, встречающееся один или несколько раз в таблицах без индексов для объединения. Это действительно замедляет ход событий. Чтобы перемотать вперед, способ исправить это с подсказкой. Добавьте следующее в конце запроса:

OPTION (MERGE JOIN, HASH JOIN)

Это обычно исправляло эту проблему для меня в прошлом.

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


1
План выполнения действительно использует соединение с вложенным циклом. Однако, когда я помещаю подсказку, как вы предлагаете, я получаю эту ошибку: «Обработчику запросов не удалось создать план запроса из-за подсказок, определенных в этом запросе. Повторите запрос без указания каких-либо подсказок и без использования SET FORCEPLAN». Конечно, когда я добавляю OPTION (LOOP JOIN), он создает план выполнения, но у меня все еще есть проблема с его медленным выполнением. Вы сталкивались с этой проблемой? Похоже, он думает, что нужно циклическое соединение.

@Trevor. , , Нет, я на самом деле не видел эту проблему. Возможно, ваш запрос выполняет какие-то неравные операции (не используя знаки равенства), и оптимизатор должен использовать соединения с вложенными циклами.
Гордон Линофф

3

Обычно это отсутствующий индекс, вызывающий подобные проблемы.

Обычно я выполняю запрос с использованием SQL Management Studio и включаю «Включить фактический план выполнения (CTRL + M)» и выясняю, какое объединение имеет наибольший процент.

Приложение не фокусируется на узких местах, но вы можете найти его «быстро», просто взглянув на результат.

пример здесь: 48PercentForTop


2
индекс не будет внезапно «пропадать», поэтому, хотя это может улучшить производительность, это не объясняет проблему
Fowl

3

Недавно я столкнулся с той же проблемой, которая привела меня на эту страницу.

@MartinSmith был о чем-то, когда он рекомендовал обновить вашу статистику и объяснить план. Я хотел бы добавить, что вы должны также постараться убедиться, что вы смотрите на запущенные задания / запросы, которые могут создавать блокировки и тем самым замедлять время отклика.

В моем случае виновником была сбор статистики по работе. По какой-то причине он не завершился в окне, которое должно было появиться, и продолжал работать, когда пользователи возобновили работу. Я нашел процесс, убил его, и запросы снова начали отвечать.

Я надеюсь, что это помогает кому-то еще


0

Вам также необходимо проверить, выполняются ли какие-либо резервные копии сервера или задания архивирования \ индексирования, когда вы видите проблему с производительностью в T-SQL \ Процедура.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.