The NoteBook of EricKong

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks

     扫描与查找操作均是SQL Server从表或索引中读取数据采用的迭代器,这些也是SQL Server支持的最基本的运算.几乎在每一个查询计划中都可以找到,因此理解它们的不同是很重要的,扫描是在整张表上进行处理,而索引是在整个页级上进行处理,而查找则返回特定谓词上一个或多个范围内的数据行
      下面让我们看一个扫描的例子(这里使用Northwind数据库)
        SELECT [OrderId] FROM [Orders] WHERE [RequiredDate] = '1998-03-26'
        在Orders表中,并不存在对RequiredDate列的索引,因此,SQL Server必须读取Orders表的每一行来估计每一行的RequiredDate谓词,如果满足该谓词条件(即找到包含’1998-03-26’的记录),则返回该行数据.
        为了最大化提升性能,SQL Server尽可能地使用扫描迭代器来估计该谓词,然而,如果该谓词过于复杂或开销过大,SQL Server或许使用别的筛选迭代器来估计.以下是WHERE关键字中的文本计划的过程:
|--Clustered Index Scan(OBJECT:([Orders].[PK_Orders]),
  WHERE:([Orders].[RequiredDate]='1998-03-26'))
下图描述了该操作的流程图:

    由于扫描表的每一行数据,不论满足与否,因此,其查询开销对表中的总记录数是均衡的,当表中的数据很少或满足谓词的行比较多时,采用扫描操作有效,如果表中数据量比较大或满足谓词的行较少时,使用扫描将读取更多的页面或执行更多的I/O操作来获取数据,这显而不是最有效的方法.   
     下面让我们看一个关于索引查找的例子,下面的例子在OrderdDate列上创建了索引:
   SELECT [OrderId] FROM [Orders] WHERE [OrderDate] = '1998-02-26'

         这次SQL Server能够使用索引查找来直接找到满足谓词的那些记录行,这里称该谓词为"查找"谓词.大多数情况下,SQL Server并不显式地估计"查找"谓词,而索引确保了"查找"操作仅返回满足的数据行,以下是"查找"谓词的文本计划:

|--Index Seek(OBJECT:([Orders].[OrderDate]),

  SEEK:([Orders].[OrderDate]=CONVERT_IMPLICIT(datetime,[@1],0)) ORDERED FORWARD)

注意:SQL Server自动使用@1参数替换查询文本中的参数

    由此看来,查找仅扫描满足该谓词的数据页,其查询开销显然要比表中总记录数的开销低,因此,对于高选择度的查询谓词操作,查找通常是最有效的策略.也就是说,对于估计大表中的数据时,使用查找谓词是比较有效率的.

    SQL Server将扫描与查找进行区分,如同将在堆(无聚集索引的对象)上扫描,聚集索引上的扫描,非聚集索引上的扫描进行分区.下表说明了这些出现在的查询计划中的扫描与查找运算.

 

扫描

查找

表扫描

 

聚集索引

聚集索引找描

聚集索引查找

非聚集索引

索引扫描

索引查找

可查找的谓词与覆盖列

    SQL Server在执行索引查找之前,它需要确定索引的键是否满足查询中的谓词,我们称该谓词为"可查找的谓词",SQL Server必须确定该索引是否包含或"覆盖"查询中引用的列集合.下面描述了如何确定哪个谓词是可查找的,哪个谓词不是可查找的,哪些列需要索引覆盖.

单列索引

   在单列索引上判断谓词是否是可查找的是很容易的,SQL Server使用单列索引来响应多数简单的比较(包括相等和不等(大于,小于等))或者更复杂的表达式,如在列上运算的函数和LIKE %谓词,这些运算符将阻止SQL Server使用索引查找.

例如,假设我们在Col1列上创建了单列索引,可以在以下谓词上进行索引查找:

Ø [Col1] = 3.14

Ø [Col1] > 100

Ø [Col1] BETWEEN 0 AND 99

Ø [Col1] LIKE 'abc%'

Ø [Col1] IN (2, 3, 5, 7)

然页,在以下谓词上将不能使用索引查找:

Ø ABS([Col1]) = 1

Ø [Col1] + 1 = 9

Ø [Col1] LIKE '%abc'

下面我通过一些例子来介绍单列索引:

首先创建一些架构对象:
create table person
(id int, last_name varchar(30), first_name varchar(30))

create unique clustered index person_id
on person (id)
create index person_name
on person (last_name, first_name)

    以下是三个查询及其各自的文本查询计划,第一个查询在person_name索引上进行查找,第二个查询首先在第一个键列上进行索引查找,然后使用residual谓词来估计first_name,第三个查询不能使用索引查找,而是使用了索引扫描来处理residual谓词.

select id from person where last_name = 'Doe' and first_name = 'John'

 |--Index Seek(OBJECT:([person].[person_name]), SEEK:([person].[last_name]='Doe' AND [person].[first_name]='John'))

 

select id from person where last_name > 'Doe' and first_name = 'John'

 |--Index Seek(OBJECT:([person].[person_name]), SEEK:([person].[last_name] > 'Doe'), WHERE:([person].[first_name]='John'))

 

select id from person where last_name like '%oe' and first_name = 'John'

 |--Index Scan(OBJECT:([person].[person_name]), WHERE:([person].[first_name]='John' AND [person].[last_name] like '%oe'))

 

上面三条查询的图形查询计划:

posted on 2010-08-18 16:16 Eric_jiang 阅读(2355) 评论(0)  编辑  收藏 所属分类: 数据库

只有注册用户登录后才能发表评论。


网站导航: