Почему мой запрос неожиданно стал медленнее, чем вчера?

76

[Приветствия]

(отметьте один)

[ ] Well trained professional, [ ] Casual reader, [ ] Hapless wanderer,

У меня есть (отметьте все подходящие варианты)

[ ] query [ ] stored procedure [ ] database thing maybe  

это работало нормально (если применимо)

[ ] yesterday [ ] in recent memory [ ] at some point 

но внезапно стал медленнее.

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

В чем проблема, что я должен делать, и какую информацию я могу предоставить, чтобы получить некоторую помощь?

[*Insert appropriate closing remarks*]
Эрик Дарлинг
источник

Ответы:

88

Уважаемый [ваше имя здесь]!

О нет, мне жаль это слышать! Давайте начнем с некоторых основ, которые помогут вам быстро освоиться.

То, с чем вы сталкиваетесь, называется параметризацией

Это выход из странной странной проблемы. Имя скатывается с языка. Как немецкое слово для белка.

И это обычно твой друг.

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

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

Например:

  • Люди в футболках CrossFit, которые не пострадали: ноль

  • Люди в рубашках CrossFit, которые морщатся, когда морщатся: Все

Очевидно, что одно выполнение этого кода должно было бы выполнять гораздо больше работы, чем другое, и планы запросов, которые вы хотели бы выполнять совершенно по-другому, выглядели бы совершенно по-другому.

Что я против?

Это действительно трудная проблема для поиска, тестирования и исправления.

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

Быстрые исправления

Иногда все, что вам нужно, это немного ясности. Вернее, кеш вашего плана делает.

Если это хранимая процедура

Попробуйте запустить EXEC sys.sp_recompile @objname = N'schema.procname'. Это заставит процедуру перекомпилировать новый план при следующем запуске.

Что это не исправит:

  • Процессы, в настоящее время выполняющие это.

Что это не гарантирует:

  • Следующий процесс, который запускается после перекомпиляции, будет использовать параметр, который даст вам хороший план.

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

Если это параметризованный запрос

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

Самый простой способ понять эту команду - запустить sp_BlitzWho *! Есть столбец с именем «Исправить сниффинг параметров», в котором есть команда для удаления одного плана из кэша. Это имеет те же недостатки, что и перекомпиляция.

Что это не исправит:

  • Процессы, в настоящее время выполняющие это.

Что это не гарантирует:

  • Следующий процесс, который запускается после перекомпиляции, будет использовать параметр, который даст вам хороший план.

Мне все еще нужна помощь!

Нам понадобятся следующие вещи:

  • Хороший план запроса, если это возможно
  • Плохой план запроса
  • Используемые параметры
  • Вопрос в вопросе
  • Определения таблиц и индексов

Получение планов запроса и запроса

Если запрос выполняется, вы можете использовать sp_BlitzWho * или sp_WhoIsActive для захвата выполняющихся в данный момент запросов.

EXEC sp_BlitzWho;

EXEC sp_WhoIsActive @get_plans = 1;

NUTS

Если запрос в настоящий момент не выполняется, вы можете проверить его в кэше плана, используя sp_BlitzCache *.

Если вы используете SQL Server 2016+ и у вас включен Query Store, вы можете использовать sp_BlitzQueryStore *.

EXEC dbo.sp_BlitzCache @StoredProcName = 'Your Mom';

EXEC dbo.sp_BlitzQueryStore @StoredProcName = 'Your Mom';

Это поможет вам отследить кэшированные версии вашей хранимой процедуры. Если это просто параметризованный код, ваш поиск немного сложнее. Это может помочь, хотя:

EXEC dbo.sp_BlitzCache @QueryFilter = 'statement';

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

NUTS

Самый простой способ поделиться планами - использовать Paste The Plan * или выгрузить XML в pastebin. Чтобы получить это, нажмите на один из тех, кто приглашает синие щелкающие столбцы. Ваш план запроса должен появиться на новой вкладке SSMS.

NUTS

Если вам не терпится поделиться кодом и запросом своей компании, вы можете воспользоваться бесплатным инструментом Sentry One Plan Explorer для анонимизации вашего плана. Имейте в виду, что это усложняет получение помощи - анонимный код намного сложнее для чтения и понимания.

Все эти инструменты, о которых мы говорили, должны возвращать текст запроса. Вам не нужно больше ничего делать здесь.

Получить параметр (ы) немного сложнее. Если вы используете Plan Explorer , внизу есть вкладка, в которой перечислены все из них для вас.

NUTS

Если вы используете sp_BlitzCache *, есть кликабельный столбец, который дает вам оператор выполнения для хранимых процедур.

NUTS

Получение таблицы и определения индекса

Вы можете легко щелкнуть правой кнопкой мыши в SSMS, чтобы написать сценарий.

NUTS

Если вы хотите получить все в одном кадре, sp_BlitzIndex * может помочь, если вы направите его прямо на стол.

EXEC dbo.sp_BlitzIndex @DatabaseName = 'StackOverflow2010',
                       @SchemaName = 'dbo',
                       @TableName = 'Users';

Это даст вам определение таблицы (хотя и не как оператора create) и создаст операторы для всех ваших индексов.

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

Я хочу сделать это сам!

Ну круто Я рад за тебя. Вы сумасшедший человек.

Есть много способов, которыми люди думают, что они "исправляют" сниффинг параметров:

Но они действительно просто отключают анализ параметров по-разному. Это не значит, что они не могут решить проблему, они просто не могут понять причину.

Это потому, что найти причину обычно довольно сложно. Вы должны искать эти противные "проблемы качества плана".

Начиная с быстрых против медленных планов, ищите различия как:

  • Используемые индексы
  • Присоединиться к заказу
  • Серийный против параллельного

Также обратите внимание на различные операторы, которые делают ваш код чувствительным к анализу параметров:

  • Lookups
  • Сорта
  • Тип соединения
  • Предоставление памяти (и, соответственно, разливов)
  • Катушки

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

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

Если вы хотите узнать больше о сниффинге параметров:

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


Эрик Дарлинг
источник
28

Обнаружение параметров - не единственная возможная причина различной производительности запроса. Любая из следующих распространенных причин может показать те же симптомы:

  1. Распределение данных / объем изменен, пересекая точку принятия решения в дереве поиска оптимизатора
  2. Индексы / файлы были фрагментированы
  3. Статистика была обновлена ​​/ добавлена ​​/ удалена или устарела из-за изменений данных
  4. Использование памяти Windows изменено
  5. Журналы транзакций переполнены и не усекаются, что вызывает повторное расширение физического файла
  6. Схема изменена - индекс / индексированное представление / столбец / ограничение добавлено, изменено или удалено, тип данных изменен и т. Д.
  7. Настройки флага трассировки изменены
  8. Обновление Windows было применено
  9. Настройки базы данных или сервера изменены
  10. Уровень CU сервера изменен
  11. Настройки сеанса клиентского приложения изменены

Пункты 6 - 11 в этом списке могут появиться только после того, как было предпринято какое-то явное действие. Я предполагаю, что вы хотели исключить их, но часто тот, кто испытывает проблему, не знает, что кто-то еще внес изменения, и это стоит проверить, прежде чем встать на путь очистки записей кэша плана.

SQLRaptor
источник
1
Спасибо за редактирование, Пол. @sp_BlitzErik - Я не собирался давать советы по конкретным темам, просто чтобы повысить осведомленность о том, что они существуют, и, возможно, стоит проверить. Это ни в коем случае не должно умалять ваш великий пост. Вы имели дело с анализом параметров глубоко, профессионально и с хорошим настроением. Мне понравилось читать это. Я только хочу убедиться, что если кто-то здесь посетит этот пост, следуя броскому заголовку, он / она узнает об альтернативных потенциальных причинах. ИМХО, это добавляет ценность вашему посту, но если вы все же хотите, чтобы я его удалил, дайте мне знать.
SQLRaptor
Нет, совсем нет. Я бы никогда не попросил кого-то удалить ответ, который не является неправильным или вредным. Я все еще думаю, что вы могли бы добавить некоторые детали, но в конечном итоге это зависит от вас.
Эрик Дарлинг
10

Просто для добавления к существующим ответам, если они не помогли, когда «неожиданно» ваши запросы ведут себя по-другому на следующий день, проверьте:

  • Изменилась ли схема для используемых таблиц с прошлого раза? В случае SSMS, вы можете щелкнуть правой кнопкой мыши по серверу в обозревателе объектов и выбрать Reports → Standard Reports → Schema Changes History.
  • Значительно увеличилось количество предметов? Возможно, ваш запрос намного медленнее, когда в используемых таблицах много данных.
  • Кто-то еще использует базу данных одновременно с вами? Может быть, выбрать временные интервалы, где вы не мешаете работе друг друга.
  • Как выглядит системная статистика? Возможно, сервер перегрелся и начал дросселировать процессор, или на жестких дисках не хватает места или места подкачки. Может быть, есть другая аппаратная проблема, такая как пожар или наводнение в серверной комнате.
user1306322
источник
7

Другая возможность состоит в том, что ваша инфраструктурная команда использует такие инструменты, как vMotion на VMware, а виртуальная машина, поддерживающая ваш экземпляр SQL, плавно перемещается с хоста на хост, и администратор базы данных не знает об этом.

Это реальная проблема, когда ваша Инфраструктура поставляется из внешних источников ... У меня настоящий кошмар с этим.

pacreely
источник