zoukankan      html  css  js  c++  java
  • 关于索引,我们可以知道的更多 全表扫描和索引扫描

    关于索引,我们可以知道的更多 --全表扫描和索引扫描

    先建一个简单的表结构

    create table test(a int ,b datetime
    create index idx_b on test(b) 

    再来点测试数据

    declare @i int 
    declare @x int 
    set @i = 0 
    set @x = 0 
    while (@i < 1000
    begin 
    insert into test values(@i,dateadd(hour,rand(@x) * 10000,getdate())) 
    set @x = @x + rand() * 1000 
    set @i = @i + 1 
    end 


    这样的两句查询:

    select a from test 
    select 1 from test 

    可以看到前者使用全表扫描,后者使用了索引,这样一来实在是很迷惑,SQLServer为什么要对后者使用索引扫描呢?又没有过滤条件。
    其实是有原因的,因为SqlServer知道后者不会取表数据,那么对于索引树的扫描将要快于表的扫描(其实事实上未必如此),因为索引树占用的空间一般要小于表数据的空间,而小的数据读取可以减小I/O读取,要知道这是最耗时的一个操作,但实际上呢,因为当前索引使用的是占数据行空间绝大多数的b字段,所以在这里,第二条语句要慢于第一条。

    如果不信,那么继续,先对表加一个a字段的非聚集索引:

    create index idx_a on test(a) 

    然后再执行上面两个查询,这次SQLServer很聪明地选择了占用空间更小的idx_a索引扫描来对第二句查询进行执行,但是等等,怎么还是第一个查询执行得更快???其实原因很简单,对索引树的遍历比对表空间的遍历要更复杂,因为索引树用中间节点来存放数据(大家看看B树的结构就明白了,SQLServer使用的是B-树),只有叶子节点才指向具体的数据(这个指向会因为有没有聚集索引而不同,这个以后会讲到),因此第一句的全表扫描要快一些,这是不是表示SQLServer选择了错误的扫描方式呢?非也,现在试着把数据加大到10000条,再执行,看到了吧,索引扫描要快(此处忽略对字段a的select操作成本,因为此成本开销实在是非常小)。


    再来执行两条SQL语句:

    select * from test where b is null 
    select * from test where b is not null 

    可以看到,这两个查询都利用了索引,在此更正我上一篇BLOG中的错误,SQLServer是会将NULL值存入索引树的,这和它的数据结构有关,通过NULL位图,它可以处理NULL值,而索引叶子节点中的数据存放结构和表数据行的结构是大同小异的,而Oracle是不会存放NULL到索引的。

    好了,先吃饭了,接下来的东西以后再讲。


    引用自:
    http://www.cnblogs.com/progame/archive/2005/01/14/91780.html

  • 相关阅读:
    Leetcode 493.翻转对
    Leetcode 491.递增子序列
    Leetcode 488.祖玛游戏
    Leetcode 486.预测赢家
    Leetcode 483.最小好进制
    Leetcode 482.密钥格式化
    商品期货投资的那些事(八)为你的套利头寸买个保险
    商品期货投资的那些事(七)趋势套利震荡投机、直道飘移弯道超越
    商品期货投资的那些事(五)做空焦煤焦炭?你是想跟发改委作对吗?
    商品期货投资的那些事(六)期现投资这行怎样才能赚大钱?
  • 原文地址:https://www.cnblogs.com/xiaodi/p/138822.html
Copyright © 2011-2022 走看看