SQL Server未使用带包含列的合适索引,如何优化其索引选择决策?
SQL Server查询优化器未选用匹配索引的解决方案
以下是针对该问题的可落地优化措施:
- 统计信息过时导致优化器成本估算错误
大表的统计信息更新不及时会导致优化器错误判断不同执行路径的成本,优先选择扫描聚簇索引。执行以下命令更新统计信息即可修正:-- 全量扫描更新筛选索引的统计信息,保证精度 UPDATE STATISTICS tblClaimServices idx_test1 WITH FULLSCAN; -- 更新全表统计信息 UPDATE STATISTICS tblClaimServices WITH FULLSCAN; - 非聚集索引需要回表产生额外成本
你的查询返回几乎所有字段,优化器会判断走非聚集索引后回聚簇索引查剩余字段的成本高于直接扫聚簇索引,因此不会选用该索引。解决方法是创建覆盖索引,把查询需要的所有字段都加入包含列,完全避免回表:
如果Django ORM生成的是参数化查询,-- 替换<field1、field2...>为查询中实际返回的所有字段 CREATE NONCLUSTERED INDEX idx_claimservices_valid_claimid ON tblClaimServices (ClaimID) INCLUDE (ValidityTo, <field1, field2...>) WHERE ValidityTo IS NULL;ValidityTo IS NULL被替换为参数形式,优化器无法匹配筛选索引的固定条件,可以放弃筛选索引,改用普通联合覆盖索引:
该索引对所有带ClaimID过滤条件的查询都适用,无需回表的特性会让优化器优先选择。CREATE NONCLUSTERED INDEX idx_claimservices_claimid_validityto ON tblClaimServices (ClaimID, ValidityTo) INCLUDE (<field1, field2...>); - 缓存执行计划存在参数嗅探问题
如果之前有选择性极差的ClaimID查询生成了扫描聚簇索引的执行计划,会被缓存后复用在所有同结构查询上。可以先清除该表相关的缓存执行计划:
更稳妥的方案是使用SQL Server查询存储功能:找到加索引提示后生成的高效执行计划,直接在查询存储中将该计划绑定到对应查询即可,完全不需要修改应用代码,也不会影响其他查询性能。DBCC FREEPROCCACHE ( SELECT plan_handle FROM sys.dm_exec_cached_plans CROSS APPLY sys.dm_exec_sql_text(plan_handle) WHERE text LIKE '%tblClaimServices%' );
内容的提问来源于stack exchange,提问作者Eric Darchis
相关产品推荐
相关产品推荐

