Eu tenho um SP cujo tempo de execução passou de 5 minutos > 20 minutos > 30 minutos > 53 minutos ao longo de quatro dias
As esperas estavam mostrando CPU crescente e status suspenso
Eu isolei uma única consulta que fixa a CPU
UPDATE thing.table
SET YYYYMM =
CASE
WHEN
DAY(SnapshotDate) = 1
OR
SnapshotDate = (SELECT MAX(SnapshotDate) FROM thing.table)
THEN CAST(FORMAT(DATEADD(day,-1,snapshotdate),'yyyyMM') AS INT)
ELSE NULL
END
Executei novamente, adicionando WITH (RECOMPILE)
no final - sem diferença
Eu corri UPDATE STATISTICS thing.table
- nenhuma diferença
Seria interessante executá-lo e obter o plano real, mas não quero prender a CPU por uma hora. Verifiquei sys.dm_exec_cached_plans
, mas parece ter apenas o plano estimado, não o plano real
Eu reescrevi usando CONVERT
em vez de FORMAT
(porque desconfio de coisas novas) - nenhuma diferença
Então eu reescrevi assim e levei a execução de volta para alguns segundos:
BEGIN TRAN;
UPDATE thing.table
SET YYYYMM = NULL;
UPDATE thing.table
SET YYYYMM = CAST(FORMAT(DATEADD(day,-1,snapshotdate),'yyyyMM') AS INT)
WHERE
(
DAY(SnapshotDate) = 1
OR
SnapshotDate = (SELECT MAX(SnapshotDate) FROM thing.table)
);
COMMIT TRAN;
A tabela tem cerca de 150.000 registros. É bem possível que recentemente tenha muito mais registros despejados nele, distorcendo as estatísticas, mas por que consertar isso WITH(RECOMPILE)
e não? UPDATE STATISTICS
Ele tira um instantâneo diário e possivelmente o número de registros aumentou devido ao final do mês.
Então as perguntas são:
- O plano de consulta real está armazenado em qualquer lugar?, para me poupar de executá-lo interativamente?
- Normalmente, quando uma consulta de repente leva uma eternidade, as estatísticas ficam obsoletas, mas esse não parece ser o caso aqui
Esta é a minha versão do SQL Server
Microsoft SQL Server 2014 - 12.0.4100.1 (X64) 20 de abril de 2015 17:29:27 Copyright (c) Microsoft Corporation Standard Edition (64 bits) no Windows NT 6.3 (Build 9600: ) (Hypervisor)
Aqui estão os planos de consulta lenta e rápida. Não é surpresa que eles sejam diferentes porque estão fazendo coisas diferentes:
Plano lento:
Plano Rápido:
Percebo que o slowpoke usa uma junção de loop e o fasty usa uma correspondência de hash.
Percebo que a pequena perna da junção do loop tem filtro
[Expr1006]=DB.thing.table.[SnapshotDate]
. Talvez isso não fosse mais tão pequeno?