在上面的例子中,我们了解了SQL Server如何使用索引查找来有效地获取满足谓词上的数据,然而,我们也知道非聚集索引并不覆盖表的所有列.试想一下,若我们有这样一个在非聚集索引键上的谓词查询:select查询的列并未被索引覆盖,当SQL Server在非聚集索引上查找时,将会丢失一些需要的列,与之相反,如果在聚集索引或唯上执行扫描时,将获取所有列,由于要扫描表的每一行,其操作显然不是很有效.以下的查询就是如此:
SELECT [OrderId], [CustomerId] FROM [Orders] WHERE [OrderDate] = '1998-02-26'
上面的查询与先前我们进行索引查找的用到的查询一样,唯一不同的是,这里我们选择了两列:OrderID和CustomerID.非聚集索引OrderDate列仅覆盖OrderID列.
SQL Server具有处理这一问题的方法,对于从非聚集索引中获取的每一行,它可能查询包含在聚集索引中的剩余列(这里是CustomerID),我们称该操作为"书签查询".书签查询是一个指向堆或聚集索引行的指针.SQL Server在非聚集索引中存储每一行的书签,这样一来,可以从非聚集索引直接转向基表中相对应的记录行.
下图说明了书签查询先在非聚集索引叶级上查找,然后从指向聚集索引的数据页中查找的情况。
SQL Server 2000使用指定的迭代器来实现书签查询,通过文本计划可以看出索引查找与书签查询迭代器:
|--Bookmark Lookup(BOOKMARK:([Bmk1000]), OBJECT:([Orders]))
|--Index Seek(OBJECT:([Orders].[OrderDate]),
SEEK:([Orders].[OrderDate]=Convert([@1])) ORDERED FORWARD)
下图为SQL Server 2000中的图形查询计划:
在中将使用嵌套循环联接和聚集索引查找来实现,仅当基表含有聚集索引或查询(基表是堆),中的查询计划与中的计划有些不同,但逻辑上是相同的.聚集索引查找就是通过关键来实现的一种书签查询或通过属性.以下是的图形查询计划和文本查询计划:
|--Nested Loops(Inner Join, OUTER REFERENCES:([Orders].[OrderID]))
|--Index Seek(OBJECT:([Orders].[OrderDate]),
SEEK:([Orders].[OrderDate]='1998-02-26') ORDERED FORWARD)
|--Clustered Index Seek(OBJECT:([Orders].[PK_Orders]),
SEEK:([Orders].[OrderID]=[Orders].[OrderID]) LOOKUP ORDERED FORWARD)
书签查询可以用在堆中,也可以用在聚集索引中,正如上所描述的,在SQL Server 2000中,堆上的书签查询与聚集索引上的书签查询是相同的,而在SQL Server 2005中,堆上的书签查询仍旧使用一个嵌套循环联接运算,代替了聚集索引查找,SQL Server使用一个叫做RID查询运算符.RID查询运算符包括在堆上进行书签查询的查找谓词,但是堆并不是一个索引,RID查询也不是一个索引查找.
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/355374/viewspace-495810/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/355374/viewspace-495810/