统计信息对执行计划的影响
2011-10-27 14:13
405 查看
最近遇到一个问题,示例表结构如下:
[code]usetempdb
[/code]
有一个如下的SQL查询:
[code]whereparentIdin(selectidfromTBwhereparentId=499997)
[/code]
速度非常的慢,明显是因为parentId字段无索引,然后,为其添加了索引:
这时,清下执行计划缓存,再次执行该SQL查询,执行计划如下:
看到有一个ClusteredIndexScan,这个是非常耗io的,而实事上parentId=499997的ID值只有一个,为499998,而parentId=499998的行也只有一条。
IO扫描为:
Table'TB'.Scancount10,logicalreads3882,physicalreads0,read-aheadreads0,loblogicalreads0,lobphysicalreads0,lobread-aheadreads0.
Table'Worktable'.Scancount0,logicalreads0,physicalreads0,read-aheadreads0,loblogicalreads0,lobphysicalreads0,lobread-aheadreads0.
这样看来,这个indexscan非常的不合理。此时,我们看一下索引ix_parentid上的统计信息:
可以看到一共有500000行,采样为500000行,说明在建索引ix_parentid时,应该采用的是全扫描。
接下来,单独执行了一次统计信息更新:
然后,再次查看统计信息:
此时,统计信息与之前不同,已不是全扫描,而是只采集了163584行,而且并未采集到parentid<>0的数据,再次清空执行计划缓存
然后执行本例的SQL查询,结果如下:
IO扫描为:
Table'TB'.Scancount2,logicalreads9,physicalreads0,read-aheadreads0,loblogicalreads0,lobphysicalreads0,lobread-aheadreads0.
这样来看,执行计划已正常。
在此案例中,由于parentid绝大多数值为0,只有极少数不为0,道理上来讲,并不应该创建索引,但实际业务中,也可能出现此类请求,何去何从?
setstatisticsioon
[code]usetempdb
go
--droptableTB
createtableTB(idintidentityprimarykey,parentIdint,namevarchar(50))
go
insertintoTB(parentId,name)select0,CAST(NEWID()asvarchar(50))
go499990
insertintoTB(parentId,name)select499990,CAST(NEWID()asvarchar(50))
insertintoTB(parentId,name)select499991,CAST(NEWID()asvarchar(50))
insertintoTB(parentId,name)select499992,CAST(NEWID()asvarchar(50))
insertintoTB(parentId,name)select499993,CAST(NEWID()asvarchar(50))
insertintoTB(parentId,name)select499994,CAST(NEWID()asvarchar(50))
insertintoTB(parentId,name)select499995,CAST(NEWID()asvarchar(50))
insertintoTB(parentId,name)select499996,CAST(NEWID()asvarchar(50))
insertintoTB(parentId,name)select499997,CAST(NEWID()asvarchar(50))
insertintoTB(parentId,name)select499998,CAST(NEWID()asvarchar(50))
insertintoTB(parentId,name)select499999,CAST(NEWID()asvarchar(50))
go
[/code]
有一个如下的SQL查询:
select*fromTB
[code]whereparentIdin(selectidfromTBwhereparentId=499997)
[/code]
速度非常的慢,明显是因为parentId字段无索引,然后,为其添加了索引:
createindexix_parentIdonTB(parentId)
这时,清下执行计划缓存,再次执行该SQL查询,执行计划如下:
DBCCFREEPROCCACHE
看到有一个ClusteredIndexScan,这个是非常耗io的,而实事上parentId=499997的ID值只有一个,为499998,而parentId=499998的行也只有一条。
IO扫描为:
Table'TB'.Scancount10,logicalreads3882,physicalreads0,read-aheadreads0,loblogicalreads0,lobphysicalreads0,lobread-aheadreads0.
Table'Worktable'.Scancount0,logicalreads0,physicalreads0,read-aheadreads0,loblogicalreads0,lobphysicalreads0,lobread-aheadreads0.
这样看来,这个indexscan非常的不合理。此时,我们看一下索引ix_parentid上的统计信息:
可以看到一共有500000行,采样为500000行,说明在建索引ix_parentid时,应该采用的是全扫描。
接下来,单独执行了一次统计信息更新:
UPDATESTATISTICSTBix_parentId
然后,再次查看统计信息:
此时,统计信息与之前不同,已不是全扫描,而是只采集了163584行,而且并未采集到parentid<>0的数据,再次清空执行计划缓存
DBCCFREEPROCCACHE
然后执行本例的SQL查询,结果如下:
IO扫描为:
Table'TB'.Scancount2,logicalreads9,physicalreads0,read-aheadreads0,loblogicalreads0,lobphysicalreads0,lobread-aheadreads0.
这样来看,执行计划已正常。
在此案例中,由于parentid绝大多数值为0,只有极少数不为0,道理上来讲,并不应该创建索引,但实际业务中,也可能出现此类请求,何去何从?
相关文章推荐
- SQL Server 执行计划利用统计信息对数据行的预估原理二(为什么复合索引列顺序会影响到执行计划对数据行的预估)
- 从一个SQL使用了不理想的执行计划说开,浅谈执行计划如何估算cache信息的影响及系统统计信息的收集等(2010-10-15)
- 收集统计信息中的no_invalidate选项对执行计划的影响
- SQL Server 执行计划利用统计信息对数据行的预估原理二(为什么复合索引列顺序会影响到执行计划对数据行的预估)
- 集簇因子对执行计划影响和统计信息拷贝
- 通过锁定统计信息来锁定执行计划
- 【转】如何知道执行计划使用了那些统计信息
- 统计信息失准导致CBO选错执行计划一例
- 一次ORA-4030问题诊断及解决【解决思路不错,说明了对象的统计信息与优化器的优化操作(即选择执行一个SQL语句在该优化参数环境下最佳的执行计划)间的关系】
- 6.2.3 收集执行计划统计信息
- sqlplus中显示sql执行计划和统计信息
- 在Oracle的SQL*PLUS中启用AutoTrace查看SQL执行计划和统计信息
- 执行计划基础 统计信息
- Oracle:执行计划:访问路径、表连接、提示、统计信息、绑定变量
- 统计信息不准导致执行计划出错跑不出结果,优化后只要1分钟
- 解决scott用户执行计划看不到统计信息的问题
- 为准确生成执行计划更新统计信息-analyze与dbms_stats
- ORACLE 执行计划 统计信息介绍
- ORACLE10g柱状图信息对执行计划的影响
- 是什么引起执行计划变得极其糟糕? 应该使用更新统计信息来解决它吗?