Скажу сразу , что мой вопрос / проблема выглядит похожа на эту предыдущий, но так как я не уверен , если причина или начальная информация является таким же, я решил разместить свой вопрос еще с некоторыми деталями.
Проблема под рукой:
- в неурочный час (ближе к концу рабочего дня) производственный экземпляр начинает работать беспорядочно:
- например, высокая загрузка ЦП (по сравнению с 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, в тестовой среде