首先是关于扫描的示例,如下所示:
RequiredDate列是没有索引的。所以SQL Server需要读取Orders表中的每一行,在RequiredDate中评估此谓词,如果这一行符合条件,则返回此行。
因为扫描操作会涉及表中的每一行而不管其是否符合条件,所以扫描的成本与表中的行数成正比。因此当表很小或对谓词来说有很多行符合条件时,扫描时有效的。然而,当表很大并且当大部分的行都不符合条件时,扫描就要涉及很多不必要的页和行,并且执行大量的I/O操作。
下面来看一个索引查找的例子。其谓词在OrderDate列,而这一列有一个索引。
这时SQL Server就可以使用这个索引直接搜索满足此谓词的行。这样,就可以将这个谓词看做是一个查找谓词。索引确保了查找操作符只返回符合条件的行。由于只在符合条件的行及包含这些行的页中进行,所以查找的效率与符合条件的行数、页数成正比,而与表中的总行数无关。因此查找效率取决于是否选择了合适的查找谓词。即如果一个查找谓词能够过滤表中的大部分内容,那么查找效率会大大提高。
在SQL Server中,扫描与查找的区别类似于堆扫描、聚集索引扫描与非聚集索引扫描之间的区别。
SQL Server在执行索引查找前,需要确定查询中索引关键字是否适合计算谓词。推荐使用可以作为索引查找基础的可查找谓词。同时SQL Server还需要确定索引中是否包含或覆盖了查找中所涉及的列的集合。下面将详细介绍什么样的谓词可查找,什么样的谓词不可查找,以及索引所覆盖的列。
(一) 单列索引
确定一个谓词是否能在单列索引中进行查找非常简单。SQL Server可以使用单列索引来响应大部分的简单比较,包括等价于不等价(大于、小于等),复杂一些的表达式,例如列中的函数和带有引导通配符的Like谓词,通常会让SQL Server避免使用索引查找。
例如,假设在列Coll上有一个单列索引,可以使用这个索引查找下面这些谓词:
Ø [Coll] = 3.14
Ø [Coll] > 100
Ø [Coll] between 0 and 99
Ø [Coll] like ‘abc%’
Ø [Coll] in (2,3,5,7)
但是,不能使用这个索引对下列这些谓词进行查找:
Ø [Coll] Like ‘%like’
Ø [Coll] + 1 = 9
(二) 复合索引
复合或多列索引相对来说要复杂一些。复合索引关键字的顺序很重要。它决定了索引的排序方式,并影响SQL Server使用此索引计算的查找谓词集。
排序的理解就像电话薄。电话薄就像是带有关键字(姓、名)的索引,按照姓氏来排序。如果知道某人的姓氏,就可以很容易的找到这个人。然而,如果只知道这个人的名字不知道姓氏,想要找到这个名字的人员名单就很困难,因为需要一个以名字来排序的电话薄。
同理,如果两列上存在一个索引,当第一列包含等价谓词时,就只能使用索引去满足第二列上的谓词。甚至在无法使用索引去满足第二列的谓词时,或许可以在第一列中使用。这时,为第二列引入剩余谓词。这个谓词的计算方式与其他扫描谓词类似。
例如,假设在列Col1和Col2上有一个两列索引。可以使用这个索引查找单列索引上的任何谓词。同时,也可以用它来查找其他谓词:
Ø [Col1] = 3.14 and [Col2] = ‘pi’
Ø [Coll] = ‘xyzzy’ and [Col2] <= 0
在下面这个例子中,使用索引满足列Col1上的谓词。列Col2需要一个剩余的谓词。
Ø [Col1] > 100 and [Col2] > ‘pi’
Ø [Col1] like ‘abc%’ and [Col2] = 2
在无法使用这个索引去查找下一个谓词集,甚至无法查找Col1列时,须使用其他索引(即Col2为引导时的索引),或者带有谓词的扫描。
Ø [Col2] = 0
Ø [Col1] + 1 = 9 and [Col2] between 1 and 9
(三) 确定关键字
在大多情况下,索引关键字是在Create Index语句中声明的列的集合。然而,在带有聚集索引的表中创建非唯一的非聚集索引时,如果没有明确表示它们是非聚集索引关键字的一部分,那么聚集索引的关键字会被附加到非聚集索引的关键字中。这时,就可以在这些固有的关键字中进行查找了。
(四) 已覆盖的列
表中的堆或聚集索引包含了表中所有的列。另一方面,非聚集索引只包含表中列的子集。通过限制存储在非聚集索引中的列集,SQL Server可以在每页中存储更多的行。由于减少了I/O的数量及所涉及的页的数量,这将节省磁盘空间并提高查找及扫描效率。然而,一个索引的扫描或查找操作只能返回被索引覆盖的列。
每个非聚集索引都会覆盖创建时所指定的关键列。同时,如果基本表是个聚集索引,那么这个表中每个非聚集索引都会覆盖聚集索引关键字,而不管它们是否为非聚集索引关键列的一部分。在SQL Server2005中,还可以在非聚集索引中使用Create Index语句的Include子句添加其他非关键列。需要注意的是,与索引关键字不同,排序与索引包含的列无关。