Zan*_*ane 6 sql-server sql-server-2012
所以我有一个我正在尝试调整的查询,但遇到了一个我无法理解的问题。首先是我正在使用的查询。
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
Run Code Online (Sandbox Code Playgroud)
当我运行此查询时,我得到的执行计划如下所示。
所以查询正在对这个大表进行非常大的扫描,返回 3000 万行,只是为了将其减少到 3K。它使用的索引看起来像这样。
CREATE NONCLUSTERED INDEX [IX_ImageDoc_DocType] ON [dbo].[ImageDoc]
(
[LoanMasterID] ASC,
[ImageDate] ASC,
[ImageDocType] ASC
)
Run Code Online (Sandbox Code Playgroud)
我改变了查询的方式,通过将谓词的日期部分移动到初始查询之外,从而提供更好的性能。
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
Run Code Online (Sandbox Code Playgroud)
这导致了更好的性能和明显优越的查询计划。
它正在扫描的索引现在看起来像这样。
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])
Run Code Online (Sandbox Code Playgroud)
所以这是我的问题。ImageDate 在这个索引中,为什么在我的查询中使用它会如此严重地损害性能?包含该谓词不应该更容易消除行吗?我在做什么/思考错误?
您的查询正在查找2015-04-25
AND之间的值2015-05-30
。
其中看起来你有大约 3000 万。
不幸的是,基数估计存在一个错误DATEDIFF
,其中涉及到组件颠倒的情况。
SELECT DATEADD(WK, DATEDIFF(WK, GETDATE(), 0) - 4, -30) ,
DATEADD(WK, DATEDIFF(WK, GETDATE(), 0) - 4, 0) + 5
Run Code Online (Sandbox Code Playgroud)
1784-05-15
返回到的范围1784-06-19
。极有可能表(或统计直方图)中没有该范围内的日期,因此 SQL Server 将估计扫描中不会返回任何行,当然不需要 3000 万次查找。
这是一个已修复的错误,但需要启用跟踪标志 4199。
如果不可能,您可以尝试以不同的方式重新表述谓词,以避免使用变量DATEDIFF
或将值分配给变量并使用OPTION (RECOMPILE)