这是我的查询(它是 Microsoft Axapta 查询):
(@P1 bigint)
SELECT TOP 1 T1.JOURNALNUM,T1.LINENUM,T1.ACCOUNTTYPE,T1.COMPANY,T1.TXT,
T1.AMOUNTCURDEBIT,T1.CURRENCYCODE,T1.EXCHRATE,T1.TAXGROUP,
T1.CASHDISCPERCENT,T1.QTY,T1.BANKNEGINSTRECIPIENTNAME,
-- *Snipped lots of columns in T1* --
T1.MODIFIEDDATETIME,T1.RECVERSION,T1.PARTITION,T1.RECID
FROM LEDGERJOURNALTRANS T1
WHERE (((PARTITION=123123123) AND (DATAAREAID=N'test')) AND (REVRECID=@P1))
当前执行计划:
实际上,表上有一个适当的索引。
索引列:(PARTITION,DATAAREAID,REVRECID)
我尝试了索引力。这个执行计划(index seek+key lookup)比after plan(索引扫描)要快:
我试图:
更新统计
更改了它的列顺序,例如 (REVRECID,PARTITION,DATAAREAID)
MSSQL 为什么选择聚集索引?
估计,选择大量列和谓词下推
查询的估计没有考虑到扫描的剩余谓词比从聚集索引中获取所有这些额外列的查找 + 键查找的成本更高。这导致选择聚集索引扫描 + 剩余谓词而不是索引查找。
这些关于谓词下推的估计值在SQL Server 2016 SP1中得到了改进
更新以改进对 SQL Server 2016 中涉及残留谓词下推的查询执行计划的诊断
这将添加
EstimatedRowsRead=""
到查询计划 XML,在您的情况下,如果选择了扫描,这将接近或匹配剩余谓词。这应该可以解决您的问题
残差谓词示例
读取 1.2M 行返回 0
索引扫描查询估计总成本
索引搜索查询估计总成本
由于不考虑残差谓词,这高于索引扫描估计,这就是选择性能较差的计划的原因。
主要解决方案
主要解决方案是升级到至少 SP1 以添加:
更新以改进对 SQL Server 2016 中涉及残留谓词下推的查询执行计划的诊断
由于SP2 CU6 已于2019年 3 月 19 日发布,因此您应该更快更频繁地进行修补,这将是一个更好的选择。
另一个注意事项,SQL Server 2016 的SP1添加了许多附加功能,例如内存中 OLTP、压缩、列存储索引......
其他可能值得一提或不值得一提的解决方法
OPTION(QUERYTRACEON 4138)
(也许)禁用行目标WITH(INDEX))
提示与 SQL Server 2016 SP1 的比较
在运行与您类似的查询时,强制在 SQL2016 SP1 版本上使用聚集索引:
估计的子树成本要高得多。
聚集索引扫描的估计子树成本在哪里
低
主要区别在于
在应用了SP1的 SQL 2016 上执行查询时显示。
并且在使用指定的 NC 指数进行测试时
索引搜索的 EstimatedTotalSubtreeCost (不是整个计划的总数)也很低:
并且我的测试查询的总估计子树成本非常接近您的