zoukankan      html  css  js  c++  java
  • 统计信息对执行计划的影响

    最近遇到一个问题,示例表结构如下:

    set statistics io on
    use tempdb 
    go
    --drop table TB
    create table TB (id int identity primary key, parentId int,name varchar(50))
    go
    insert into TB(parentId,name) select 0,CAST(NEWID() as varchar(50))
    go 499990
     
    insert into TB(parentId,name) select 499990,CAST(NEWID() as varchar(50))
    insert into TB(parentId,name) select 499991,CAST(NEWID() as varchar(50))
    insert into TB(parentId,name) select 499992,CAST(NEWID() as varchar(50))
    insert into TB(parentId,name) select 499993,CAST(NEWID() as varchar(50))
    insert into TB(parentId,name) select 499994,CAST(NEWID() as varchar(50))
    insert into TB(parentId,name) select 499995,CAST(NEWID() as varchar(50))
    insert into TB(parentId,name) select 499996,CAST(NEWID() as varchar(50))
    insert into TB(parentId,name) select 499997,CAST(NEWID() as varchar(50))
    insert into TB(parentId,name) select 499998,CAST(NEWID() as varchar(50))
    insert into TB(parentId,name) select 499999,CAST(NEWID() as varchar(50))
    go

    有一个如下的SQL查询:

    select * from TB 
    where parentId in (select id from TB where parentId=499997)

    速度非常的慢,明显是因为parentId字段无索引,然后,为其添加了索引:

    create index ix_parentId on TB(parentId)

    这时,清下执行计划缓存,再次执行该SQL查询,执行计划如下:

    DBCC FREEPROCCACHE 

    2011-10-27_140218

    看到有一个Clustered Index Scan ,这个是非常耗io的,而实事上parentId=499997的ID值只有一个,为499998,而parentId =499998的行也只有一条。
    IO扫描为:

    Table 'TB'. Scan count 10, logical reads 3882, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    这样看来,这个index scan非常的不合理。此时,我们看一下索引ix_parentid上的统计信息:
    2011-10-27_141843

    可以看到一共有500000行,采样为500000行,说明在建索引ix_parentid时,应该采用的是全扫描。

    接下来,单独执行了一次统计信息更新:

    UPDATE STATISTICS TB ix_parentId

    然后,再次查看统计信息:
    2011-10-27_142329

    此时,统计信息与之前不同,已不是全扫描,而是只采集了163584行,而且并未采集到parentid<>0的数据,再次清空执行计划缓存

    DBCC FREEPROCCACHE 

    然后执行本例的SQL查询,结果如下:

    2011-10-27_142501

    IO扫描为:
    Table 'TB'. Scan count 2, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    这样来看,执行计划已正常。

    在此案例中,由于parentid绝大多数值为0,只有极少数不为0,道理上来讲,并不应该创建索引,但实际业务中,也可能出现此类请求,何去何从?


    作者:nzperfect
    出处:http://www.cnblogs.com/nzperfect/
    引用或者转载本BLOG的文章请注明原作者和出处,并保留原文章中的版权信息。

  • 相关阅读:
    [古城子的房子] 贪心
    [小兔的棋盘] 组合数学
    [Triangle] Fibonacci+二分查找
    [Fibonacci] 矩阵快速幂
    [DP?]素数筛+Lucas定理+费马小定理
    react本地开发关闭eslint检查
    react 不同js文件里公用同一个变量
    js学习笔记
    node内存扩展,前端项目运行时报内存不足的错误
    Gitee码云通过WebHooks实现自动同步代码部署
  • 原文地址:https://www.cnblogs.com/nzperfect/p/2226510.html
Copyright © 2011-2022 走看看