Então, eu tenho essa consulta que estou tentando ajustar e estou enfrentando um problema que estou tendo problemas para entender. A primeira é a consulta que estou usando.
SELECT
si.LoanNbr AS [LoanNumber],
fi.[SvcClientNbr] AS ClientID,
si.LoanMasterID,
si.LoanSrcCode AS [LoanSourceCode],
fi.LoanPurpCode,
fi.[PropState] AS [Property State],
im.ImagedocumentID AS [Image Document ID],
-- im.requestID AS [Request ID],
CONVERT(VARCHAR(10),im.[ImageDate],101) AS ImageDate,
im.[PageCount],
im.[SignatureInd]
FROM dbo.NotMybaseTable Si
INNER JOIN dbo.NotMyTableName fi
ON si.LoanMasterID = fi.LoanMasterID
INNER JOIN [dbo].[ImagedDocument] im
ON si.loanmasterid = im.loanmasterid
AND im.[DocTypeCode] = '10112'
WHERE CASE WHEN si.loansrccode = 'CORE' AND Im.[SignatureInd] IN ('Y') THEN 1
WHEN si.FundingSysCode = 'LIS' and CASE WHEN si.loansrccode = 'CORE' THEN 0 ELSE 1 END = 1 THEN 1
ELSE 0 END = 1
AND [ImageDate] BETWEEN DATEADD(WK, DATEDIFF(WK, 0, GETDATE()) - 4, -30) AND DATEADD(WK, DATEDIFF(WK, 0, GETDATE()) - 4, 0) + 5
Quando executo esta consulta, o plano de execução que recebo é assim.
Portanto, a consulta está fazendo uma varredura muito grande nessa tabela grande, retornando 30 milhões de linhas apenas para reduzi-la a 3K. O índice que está usando se parece com isso.
CREATE NONCLUSTERED INDEX [IX_ImageDoc_DocType] ON [dbo].[ImageDoc]
(
[LoanMasterID] ASC,
[ImageDate] ASC,
[ImageDocType] ASC
)
Alterei a consulta de uma maneira que oferece um desempenho muito melhor, movendo a parte da data do predicado para fora da consulta inicial dessa maneira.
select
*
from (
SELECT
si.LoanNbr AS [LoanNumber],
fi.[SvcClientNbr] AS ClientID,
si.LoanMasterID,
si.LoanSrcCode AS [LoanSourceCode],
fi.LoanPurpCode,
fi.[PropState] AS [Property State],
im.ImagedocumentID AS [Image Document ID],
CONVERT(VARCHAR(10),im.[ImageDate],101) AS ImageDate,
im.[PageCount],
im.[SignatureInd]
FROM dbo.NotMybaseTable Si
INNER JOIN dbo.NotMyTableName fi
ON si.LoanMasterID = fi.LoanMasterID
INNER JOIN [dbo].[ImagedDocument] im
ON si.loanmasterid = im.loanmasterid
AND im.[DocTypeCode] = '10112'
WHERE CASE WHEN si.loansrccode = 'CORE' AND Im.[SignatureInd] IN ('Y') THEN 1
WHEN si.FundingSysCode = 'LIS' and CASE WHEN si.loansrccode = 'CORE' THEN 0 ELSE 1 END = 1 THEN 1
ELSE 0 END = 1
) as F
WHERE [ImageDate] BETWEEN DATEADD(WK, DATEDIFF(WK, 0, GETDATE()) - 4, -30) AND DATEADD(WK, DATEDIFF(WK, 0, GETDATE()) - 4, 0) + 5
Isso resultou em um desempenho muito melhor e um plano de consulta obviamente superior.
O índice que está digitalizando agora se parece com isso.
CREATE NONCLUSTERED INDEX [IX_ImageLoanDoc_SystemName_ICMPDocTypeCode] ON [dbo].[ImageDoc]
(
[SystemName] ASC,
[ICMPDocTypeCode] ASC,
[LoanMasterID] ASC,
[ImageDate] ASC
)
INCLUDE ( [ImageDocumentID],
[ImageDocType],
[BatchName],
[SignatureInd],
[ICMPDocCategoryCode],
[ICMPDocSubTypeCode])
Então aqui está a minha pergunta. Com ImageDate estando neste índice, por que tê-lo em minha consulta prejudica tanto o desempenho? A inclusão desse predicado não deveria facilitar a eliminação de linhas? O que estou fazendo/pensando incorretamente?
Sua consulta está procurando valores entre
2015-04-25
AND2015-05-30
.Dos quais parece que você tem cerca de 30 milhões.
Infelizmente, há um bug com as estimativas de cardinalidade
DATEDIFF
onde os componentes são invertidos.Retorna um intervalo de
1784-05-15
até1784-06-19
. É extremamente provável que você não tenha datas nesse intervalo na tabela (ou histograma de estatísticas), portanto, o SQL Server estimará que nenhuma linha será retornada da verificação e certamente não haverá necessidade de 30 milhões de pesquisas.Este é um bug corrigido, mas requer o sinalizador de rastreamento 4199 habilitado.
Se isso não for possível, você pode tentar reformular o predicado de uma maneira diferente que evite o uso
DATEDIFF
ou a atribuição de valores a variáveis e usandoOPTION (RECOMPILE)
ImageDate no índice não é usado porque sua condição sobre ImageDate diz respeito a uma função ("DATEADD"). Em geral, os sistemas não usam índices sobre atributos se a condição contiver uma função que é avaliada no momento da execução da consulta.