一个很简单的查询为什么没用到非聚集索引?

Lansie 2013-03-05 11:23:50
有一张近80个字段,记录数为500w的表t,其中有自增长主键的聚集索引index1,和字段A,B,C的非聚集索引index2,A值的个数接近500w

现有三个查询
1 select A,B,C,D from t where A=A1 index2 seek
2 select A,B,C,D from t where A<A1 index1 scan 160 rows
3 select A,B,C from t where A<A1 index2 seek

现在的问题为什么查询2没用到index2,而直接对index1进行scan,造成效率非常低下
谢谢!
...全文
136 点赞 收藏 11
写回复
11 条回复
昵称被占用了 2013年03月05日
看下第一个查询的执行计划,应该除了index2 seek外,还有一个index1的键查找过程 第二个查询如何选择主要看A1的值处在所有A的值得位置,如果A<A1的数量足够小,应该会选择index2 seek+index1 seek,否则会选择index1 scan
回复 点赞
szm341 2013年03月05日
非聚集索引查询其他列时,是先查询非聚集索引中的聚集索引键,然后通过聚集索引键再查询其他列值(大概意思吧呵呵),如果优化器觉得查询的非索引列的值过多超过某个阈值的话就会变成全表扫描了吧,记得这个阈值似乎通过查询与查询计划,不断缩小范围可以检测到吧
回复 点赞
Lansie 2013年03月05日
谢谢各位的答复。 单单这个案例的解决办法是比较简单,但实际情况需要的字段很多,如果都include的话,这个索引会很大而且影响表的其它操作。 而且我想知道sql引擎是如何考虑的,从结果来看,index1 scan的效率远远低于index2 seek,即便多了一个字段D,也应该index2 seek后再去主表取字段D
回复 点赞
昵称被占用了 2013年03月05日
原因是index2没有包含字段d,你的结果需要字段d,优化器认为不如直接scan index1 如果2005+,如楼上修改index2增加包含列即可
回复 点赞
szm341 2013年03月05日
可能数据存储结构使得优化器觉得不能通过索引快速检索到多量的D列值吧
回复 点赞
水族杰纶 2013年03月05日
--try create index idx_t_A_B_C on t(a,b,c) inclue(d)
回复 点赞
szm341 2013年03月05日
引用 10 楼 英杰 的回复:
更新一下索引统计信息 清楚一下执行计划缓存 然后再看看,如果不行就强制他使用index2
生产环境千万不要清除计划缓存!
回复 点赞
押宝小旋风 2013年03月05日
更新一下索引统计信息 清楚一下执行计划缓存 然后再看看,如果不行就强制他使用index2
回复 点赞
KevinLiu 2013年03月05日
因为你的INDEX 2
引用 7 楼 Lansie 的回复:
引用 6 楼 Haiwer 的回复:看下第一个查询的执行计划,应该除了index2 seek外,还有一个index1的键查找过程 第二个查询如何选择主要看A1的值处在所有A的值得位置,如果A<A1的数量足够小,应该会选择index2 seek+index1 seek,否则会选择index1 scan 第一个查询是index2 seek+key lookup ……
你看看你的执行计划SQL Server 预估返回的行数是不是跟真实行数有偏差。可能是因为统计信息问题。
回复 点赞
發糞塗牆 2013年03月05日
1、key lookup大部分情况下是某些列没有索引,要把select和where中出现的列用include包住。 2、那是因为优化器觉得找不到比scan更好的方式,所以没有“用”索引。也证明索引没用上或者缺失了索引。
回复 点赞
Lansie 2013年03月05日
引用 6 楼 Haiwer 的回复:
看下第一个查询的执行计划,应该除了index2 seek外,还有一个index1的键查找过程 第二个查询如何选择主要看A1的值处在所有A的值得位置,如果A<A1的数量足够小,应该会选择index2 seek+index1 seek,否则会选择index1 scan
第一个查询是index2 seek+key lookup 第二个查询的结构是160条记录,远远小于总共400w的记录数,但执行计划还是index1的scan,不知是什么原因
回复 点赞
发动态
发帖子
疑难问题
创建于2007-09-28

9309

社区成员

12.1w+

社区内容

MS-SQL Server 疑难问题
社区公告
暂无公告