• 统计信息对执行计划的影响


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

    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的文章请注明原作者和出处,并保留原文章中的版权信息。

  • 相关阅读:
    jsp和servlet有什么区别?
    JavaScript中null、undefined有什么区别?
    Java中的信号量Semaphore
    Java中实现线程通信方式有哪些?
    说说对于sychronized同步锁的理解
    线程的run()方法和start()方法有什么区别?
    高并发大型网站架构设计
    高并发高流量网站架构(转)
    构建高并发高可用的电商平台架构实践
    自己搭建CDN服务器静态内容加速-LuManager CDN使用教程
  • 原文地址:https://www.cnblogs.com/nzperfect/p/2226510.html
Copyright © 2020-2023  润新知