Бесконечный поиск в магазине запросов

10

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

Проблема под рукой:

  • в неурочный час (ближе к концу рабочего дня) производственный экземпляр начинает работать беспорядочно:
    • например, высокая загрузка ЦП (по сравнению с 30% она выросла примерно вдвое и продолжала расти)
    • увеличено количество транзакций в секунду (хотя загрузка приложения не изменилась)
    • увеличено количество бездействующих сеансов
    • странные события блокировки между сессиями, которые никогда не отображали это поведение (даже чтение незафиксированных сессий вызывало блокировку)
    • лучшие ожидания интервала были защелкой страницы на 1-м месте с блокировками на 2-м месте

Начальное расследование:

  • Используя sp_whoIsActive, мы увидели, что запрос, выполняемый нашим инструментом мониторинга, решает работать очень медленно и захватывает много ЦП, чего раньше не было;
  • его уровень изоляции считывался незафиксированным;
  • мы посмотрели на план, мы увидели дурацкие цифры: StatementEstRows = "3.86846e + 010" с примерно 150 ТБ предполагаемых данных, которые должны быть возвращены
  • мы подозревали, что причиной была функция мониторинга запросов инструмента мониторинга, поэтому мы отключили эту функцию (мы также открыли тикет у нашего провайдера, чтобы проверить, знают ли они о какой-либо проблеме)
  • с того первого события это происходило еще несколько раз, и каждый раз, когда мы убиваем сессию, все возвращается на круги своя;
  • мы понимаем, что запрос чрезвычайно похож на один из запросов, используемых MS в BOL для мониторинга хранилища запросов - запросы, которые недавно снизились в производительности (сравнивая различные моменты времени)
  • мы выполняем один и тот же запрос вручную и видим одно и то же поведение (использование процессора увеличивается, увеличивается время ожидания защелки, неожиданные блокировки и т. д.)

Виновный запрос:

Select qt.query_sql_text, 
    q.query_id, 
    qt.query_text_id, 
    rs1.runtime_stats_id AS runtime_stats_id_1,
    interval_1 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi1.start_time), 
    p1.plan_id AS plan_1, 
    rs1.avg_duration AS avg_duration_1, 
    rs2.avg_duration AS avg_duration_2,
    p2.plan_id AS plan_2, 
    interval_2 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi2.start_time), 
    rs2.runtime_stats_id AS runtime_stats_id_2
From sys.query_store_query_text AS qt 
Inner Join sys.query_store_query AS q 
    ON qt.query_text_id = q.query_text_id 
Inner Join sys.query_store_plan AS p1 
    ON q.query_id = p1.query_id 
Inner Join sys.query_store_runtime_stats AS rs1 
    ON p1.plan_id = rs1.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi1 
    ON rsi1.runtime_stats_interval_id = rs1.runtime_stats_interval_id 
 Inner Join sys.query_store_plan AS p2 
    ON q.query_id = p2.query_id 
Inner Join sys.query_store_runtime_stats AS rs2 
    ON p2.plan_id = rs2.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi2 
    ON rsi2.runtime_stats_interval_id = rs2.runtime_stats_interval_id
Where rsi1.start_time > DATEADD(hour, -48, GETUTCDATE()) 
    AND rsi2.start_time > rsi1.start_time 
    AND p1.plan_id <> p2.plan_id
    AND rs2.avg_duration > rs1.avg_duration * 2
Order By q.query_id, rsi1.start_time, rsi2.start_time

Настройки и информация:

  • SQL Server 2016 SP1 CU4 Enterprise в кластере Windows Server 2012R2
  • Query Store включен и настроен по умолчанию (настройки не изменены)
  • база данных импортирована из экземпляра SQL 2005 (и все еще на уровне совместимости 100)

Эмпирическое наблюдение:

  • из-за крайне дурацкой статистики мы взяли все объекты * plan_persist **, использованные в неверно оцененном плане (еще нет фактического плана, потому что запрос не был выполнен), и проверили статистику, некоторые индексы, используемые в плане, не имели статистики (DBCC SHOWSTATISTICS ничего не возвращал, выбор из sys.stats показал функцию NULL stats_date () для некоторых индексов

Быстрое и грязное решение:

  • вручную создать недостающую статистику по системным объектам, связанным с Query Store или
  • принудительно выполнить запрос, используя новый CE (traceflag), который также создаст / обновит необходимую статистику или
  • измените уровень совместимости базы данных на 130 (по умолчанию будет использоваться новый CE)

Итак, мой настоящий вопрос будет:

Почему запрос в хранилище запросов может вызвать проблемы с производительностью всего экземпляра? Мы находимся на территории с ошибками в Query Store?

PS: Я скоро выложу несколько файлов (экраны печати, статистику ввода-вывода и планы).

Файлы добавлены в Dropbox .

План 1 - начальный дурацкий расчетный план в производстве

План 2 - фактический план, старый CE, в тестовой среде (такое же поведение, та же дурацкая статистика)

План 3 - фактический план, новый CE, в тестовой среде

Мэриан
источник
1
Мы закончили тем, что отключили хранилище запросов, мы не уверены, что было основной причиной (у нас было более 1 проблемы наверняка). С моей стороны, ЦП будет наращивать все, что мы нажимали, чтобы отобразить статистику из хранилища запросов.
A_V

Ответы:

6

Как я сказал в ответе, эмпирический тест показал, что существуют индексы для системных объектов sys.plan_persisted * без какой-либо (никакой) статистики, созданной над ними. Я подозреваю, что это связано с тем, что база данных была перенесена из экземпляра SQL 2005 и некоторое время поддерживалась на уровне совместимости 100, поэтому новый CE не использовался.

Проверка количества строк:

Select count(1) from NoNameDB.sys.plan_persist_runtime_stats with (nolock) --60362   
Select count(1) from NoNameDB.sys.plan_persist_plan with (nolock) --1853    
Select count(1) from NoNameDB.sys.plan_persist_runtime_stats_interval with (nolock) --671    
Select count(1) from NoNameDB.sys.plan_persist_query with (nolock) --1091    
Select count(1) from NoNameDB.sys.plan_persist_query_text with (nolock) --911

Это показало, что первоначальные оценки были неверными. Выполнено с подключением к ЦАП, в противном случае таблицы недоступны для запроса.

Статистика проверки:

DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats_interval', plan_persist_runtime_stats_interval_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_query', plan_persist_query_cidx)    
DBCC SHOW_STATISTICS ('sys.plan_persist_query_text', plan_persist_query_text_cidx);

Это показало, что некоторые индексы имели пустую статистику (отсутствует, нет, ноль).

Начальное исправление:

UPDATE STATISTICS sys.plan_persist_runtime_stats WITH fullscan;
UPDATE STATISTICS sys.plan_persist_plan WITH fullscan;
UPDATE STATISTICS sys.plan_persist_runtime_stats_interval WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query_text WITH fullscan;

Этот вид исправил статистику и завершил запрос за 10-12 секунд.

Второе исправление :

(проверено только в тестовой среде) и, скорее всего, правильным, поскольку он показал лучшую статистику для запроса, было изменение уровня совместимости базы данных до 130. Конечным результатом было то, что запрос завершился примерно через 10-12 секунд с нормальная числовая статистика (10 тыс. строк).

Промежуточное исправление :

DBCC TRACEON (2312) -- new CE

Некоторая связанная справка о статистике по системным скрытым таблицам.

Мэриан
источник
3

Основная проблема, которая видна, если вы откроете фактический план в SSMS и посмотрите на использование ЦП (или изучите XML), это узел 32, TVF. Причиной медленных запросов в Query Store является повторный доступ к TVF в памяти .

Стоимость ТВФ

Неважно, сколько строк возвращено из этих TVF, только количество обращений к ним. Исправление будет тем, что вы можете сделать, чтобы оттолкнуть ваши планы от прочтения их несколько раз.

Исходя из моей ограниченной отладки (как по навыкам, так и по затраченному времени), моя гипотеза состоит в том, что вся память, выделенная для конкретного компонента в памяти данных хранилища запросов, сканируется при каждом выполнении TVF. Я не был в состоянии влиять на это распределение памяти либо sp_query_store_flush_dbили DBCC FREESYSTEMCACHE.

Успешные обходные пути на данный момент включают в себя руководства по планам, подсказки ( OPTION(HASH JOIN, LOOP JOIN)пока что мне это хорошо работало) и выполнение запросов к хранилищу запросов на узле AG, доступном только для чтения.

Форрест
источник