聚集索引是一种特殊的平衡树。这种平衡树与前面的平衡树相比,差别在于索引的叶子级。在聚集索引中,叶子级并不包括索引键和指针;它们就是数据本身。这个差异意味着数据并不存储在堆结构中。它们存储在索引的叶子级,并按索引键进行排序。这种设计具有两个优点:
l SQL Server不需要依据指针来访问数据。数据直接存储在索引中。
l 数据依据索引键排序,这是主要的优点。无论什么时候,只要SQL Server需要依据索引键排序数据,都不必再执行排序操作,因为数据已经排好序了。
由于数据包含在聚集索引之中,因此只能为每个表定义一个聚集索引。以下语法用于创建一个聚集索引:
CREATE [ UNIQUE ] CLUSTERED INDEX index_name
ON <object> ( column [ ASC | DESC ] [ ,...n ] )
可以看出,可以定义索引为“unique”(惟一的),这意味着两个行不能有相同的索引键值。
注意 SQL Server在一个表上创建主键或惟一性约束的时候会创建一个惟一索引。在主键定义后,如果在表中还没有定义聚集索引,SQL Server会默认为这个主键建立聚集索引。创建主键或者惟一约束时定义的索引的类型可以这样指定:在CREATE或ALTER TABLE 语句中使用CLUSTERED或NONCLUSTERED 关键字。
Ø 创建并使用聚集索引
1. 打开SQL Server Management Studio。打开“新建查询”窗口并更改数据库上下文为“AdventureWorks”。
2. 键入并执行以下语句在Orders表上创建一个聚集索引。此示例的代码包含在示例文件CreatingAndUsingClusteredIndexes.sql中。
CREATE UNIQUE CLUSTERED INDEX CLIDX_Orders_SalesOrderID
ON dbo.Orders(SalesOrderID)
3. 现在再执行前面执行过的两个SELECT语句来检验区别。要保证在执行时包括实际的执行计划。
SET STATISTICS IO ON;
SELECT * FROM dbo.Orders;
SELECT * FROM dbo.Orders
WHERE SalesOrderID =46699;
SET STATISTICS IO OFF;
4. 切换到“执行计划”选项卡。
图6.6 “执行计划”选项卡
可以看出,这里的SQL Server不再使用表扫描。现在,由于数据不再存储在堆结构中,因此SQL Server执行了索引操作。执行计划表明将使用两个主要的索引操作,它们是:
l 索引扫描 读取表中的所有数据,通过索引的叶子级所进行的扫描。由于第一个SELECT语句没有WHERE子句,因此SQL Server知道需要获取所有数据,这些数据存储在索引的叶子级上。
l 索引查找 SQL Server查找特定值的一个操作。这个操作起始于索引的根并将查询值传递给索引的分支以进行查询。
这两个操作同样可以组合起来获取一个特定范围的数据。在这种局部扫描操作中,SQL Server会首先找到范围的起始值,然后持续扫描到范围的终点值结束。
5. 切换到“消息”选项卡,如图6.7所示。
图6.7 “消息”选项卡
可以看出,第一个SELECT语句执行了与使用堆结构进行表扫描时相同的页读取操作。这并不奇怪,因为SELECT语句要求获取所有数据。因此SQL Server不得不获取所有数据。但是,第二个SELECT语句只进行了两次页读取,这比前面有了很大的改进,少读了178页。SQL Server只需在索引上进行查找,相较于在所有数据页上进行扫描,它需要的I/O操作要少得多。
6. 键入以下SELECT语句,它会按顺序获取数据。图6.8显示了执行结果。然后按“Ctrl+L”来获取估计的执行计划。
SELECT * FROM dbo.Orders
ORDER BY SalesOrderID;
SELECT * FROM dbo.Orders
ORDER BY OrderDate;
可以看出,第一个语句只执行了一次聚集索引扫描而并没有对数据进行排序。这是因为这个列是一个聚集索引键列,数据已经根据SalesOrderID进行了排序。因此,SQL Server为了按顺序获取行只需要在叶子级扫描数据并返回结果。
对于第二个查询,数据必须在获取之后进行排序。因此,在聚集索引扫描操作之后有一个在OrderDate列上进行的排序操作。由于排序操作是非常昂贵的操作,因此第二个操作的开销占据了整个查询开销的93%。所以,对于经常需要进行排序的列,最好为其定义聚集索引。经常需要进行聚合分组的列也如此,因为在进行聚合数据的时候,SQL Server首先需要依据分组条件对其进行排序。
图6.8 执行结果
现在要在OrderDetails表上构建一个复合索引。一个复合索引是一个为多个列定义的索引。索引键将依据第一个索引键列进行排序,然后是第二个,依次类推。在使用两个以上的列一起作为条件进行查询的时候,或者在需要通过多列来惟一确定一行的时候,这种索引是非常有用的。