Eu vou dizer desde o início que a minha pergunta / problema semelhante a esse anterior, mas desde que eu não tenho certeza se a causa ou a informação inicial é o mesmo, eu decidi postar minha pergunta com mais alguns detalhes.
Problema em questão:
- em uma hora estranha (próximo ao final do dia útil), uma instância de produção começa a se comportar de maneira irregular:
- CPU alta para a instância (de uma linha de base de ~ 30%, foi para o dobro e ainda estava crescendo)
- aumento do número de transações / s (embora a carga do aplicativo não tenha visto nenhuma alteração)
- aumento do número de sessões inativas
- eventos de bloqueio estranhos entre sessões que nunca exibiram esse comportamento (até mesmo as sessões não confirmadas estavam causando o bloqueio)
- as principais esperas do intervalo foram sem trava de página no 1º lugar, com bloqueios no 2º lugar
Investigação inicial:
- usando sp_whoIsActive, vimos que uma consulta executada por nossa ferramenta de monitoramento decide rodar extremamente devagar e pegar muita CPU, algo que não havia acontecido antes;
- seu nível de isolamento foi lido sem comprometimento;
- vimos o plano em que vimos números malucos: StatementEstRows = "3.86846e + 010" com cerca de 150 TB de dados estimados a serem retornados
- suspeitamos que o recurso de monitor de consulta da ferramenta de monitoramento tenha sido a causa. Por isso, desabilitamos o recurso (também abrimos um ticket com nosso provedor para verificar se eles têm conhecimento de algum problema)
- desde o primeiro evento, isso aconteceu mais algumas vezes, toda vez que matamos a sessão, tudo volta ao normal;
- percebemos que a consulta é extremamente semelhante a uma das consultas usadas pelo MS no BOL para o monitoramento do Query Store - consultas que recentemente regrediram no desempenho (comparando diferentes pontos no tempo)
- executamos a mesma consulta manualmente e vemos o mesmo comportamento (a CPU usada aumenta cada vez mais, aumenta as esperas de trava, bloqueios inesperados etc.)
Consulta culpada:
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
Configurações e informações:
- SQL Server 2016 SP1 CU4 Enterprise em um cluster do Windows Server 2012R2
- Armazenamento de consultas ativado e configurado como padrão (nenhuma configuração alterada)
- banco de dados importado de uma instância do SQL 2005 (e ainda no nível de compatibilidade 100)
Observação empírica:
- devido a estatísticas extremamente malucas, pegamos todos os objetos * plan_persist ** usados no plano estimado ruim (nenhum plano real ainda, porque a consulta nunca foi concluída) e verificamos as estatísticas, alguns dos índices usados no plano não tinham nenhuma estatística (DBCC SHOWSTATISTICS não retornou nada, selecione a partir de sys.stats mostrou a função NULL stats_date () para alguns índices
Solução rápida e suja:
- crie manualmente estatísticas ausentes nos objetos do sistema relacionados ao Query Store ou
- forçar a consulta a ser executada usando o novo CE (traceflag) - que também criará / atualizará as estatísticas necessárias ou
- altere o nível de compatibilidade do banco de dados para 130 (por padrão, ele usará o novo CE)
Então, minha verdadeira pergunta seria:
Por que uma consulta no Query Store causaria problemas de desempenho em toda a instância? Estamos em um território de bug com o Query Store?
PS: Carregarei alguns arquivos (telas de impressão, estatísticas de IO e planos) em breve.
Arquivos adicionados ao Dropbox .
Plano 1 - plano inicial maluco estimado em produção
Plano 2 - plano real, antigo CE, em um ambiente de teste (mesmo comportamento, mesmas estatísticas malucas)
Plano 3 - plano real, nova CE, em um ambiente de teste