5.4.5 索引

5.4.5 索引
如前所述,SQL Server的表默认以堆的形式存储。要从堆中检索任何记录,SQL Server 必须执行全表扫描;换句话说,它必须检查每个记录来确定是否应返冋该记录。可以想到,
这是一种效率极其低下的检索数据的方式。堆用来存储数据很好,也能有效地处理新记录,
但要在表中寻找特定数据时就没有那么好用了。这就是索引发挥作用的地方。SQL Server 支持两种基本类型的索引:聚集索引和非聚集索引。它还支持XML索引和空间索引等其
他索引类型(本章稍后将会讨论),但这些索引和普通的关系索引大不相同,后者将用来在
数据库表中定位大多数数据。
聚集和非聚集索引之间的主要区别在于索引的叶级。在非聚集索引中,叶级包含数据
的指针。在聚集索引中,叶级包含实际数据。
1 .聚集索引
表的所有数据可存储在堆中或聚集索引中。堆和聚集索引是互相排斥的。如前所述,
堆是一个无组织的表行集合,而聚集索引是一个有组织的表行集合。
电话簿的白页是聚集索引的一个绝佳的例子。白页上所有的行都按姓和名的组合进行
聚集。当浏览白页査找一个电话号码时,浏览的是索引和数据。当找到索引值时,其余的
相关数据也找到了。
对于SQL Server聚集索引来说也是如此。可以创建聚集索引来按行的特定属性或列排 序数据。冋到图书馆的例子,图书馆通过一个基于类型和/或主题的聚集索引组织大部分的
书,然后再按作者进一步细分。聚集键在索引中必须是唯一的(这是为了支持非聚集索引,
稍后会介绍),但创建索引时不必将此列标记为唯-的。当在未标记为唯一的列上创建聚集
索引时,SQL Server会生成一个隐藏列,它保存一个名为唯一标识符(uniqueifier)的4 字节内 部值来唯一标识重复的聚集索引键。聚集索引的叶级是实际的数据行,而不是数据的指针。

2 .非聚集索引
非聚集索引更像是一本书后面的索引。当找到索引值时,并不能得到实际数据行,只
是获得指定实际数据行的位置的指针。叶级页中包括的指针类型将取决于非聚集索引是构
建在堆还是聚集索引之上。
堆上的非聚集索引
当在一个以堆形式组织的表上构建非聚集索引时,索引列根据指向数据实际位置的指
针分类。该指针由文件ID、页 ID和数据所在的页槽号组成。例如,如果数据是第一个文
件中第84 593页上的第20条记录,那么SQL将使用指针值1:84593:20。这 使 SQL Server
能够在索引找到数据之后快速访问数据。
例如,让我们回到图书馆的例子。如果收入无组织化的图书馆的每本书的物理位置都
按其在书架上的放置位置记录在索引巾,那么可以参照此索引来找到书,而不必搜索所有
书架。这种技术的不利之处就是,类似的记录(在图书馆例子中就是类似的书)可能放在完
全不同的地方。例如,搜索有关SQL Server 2008的书可能会返回好几本,而每本又位于图 书馆中的两端。如果所有SQL Server的书都放在一起,那么找到它们花费的力气就要少很 多。对于建立在一个堆表上的简单的单列索引来说,索引本身就像是一个两列的表。第一
列记录索引值,而第二列则记录从中可找到索引值的行的实际位置。
聚集索引上的非聚集索引
当在一个聚集索引上构建非聚集索引时,索引中的指针值就是数据行的聚集索引键
值。一旦定位到索引值,SQL Server就使用聚集键导航聚集索引来检索所有需要的列。 例如,在电话簿的例子中,我们知道电话簿的白页就像是SQLServer中的聚集索弓|。我住 在丙雅图东南的一个小镇上。我的电话簿在白页后面包含了一个有趣的附加索引,我把它们称
为 “灰白页”。这些“灰白页”按顺序囊括了镇卜.每一个公开的电话号码,还有号码持有人的
姓和名。这是在聚集索引上构建非聚集索引的一个非常好的例子。电话号码可以用来发现姓和
名的组合,而姓和名的组合可以用来寻找地址(如果它们在电话簿中列出来的话)。
创建聚集索引还是把记录留在堆中,这是一个通常由数据访问方式决定的设计决策。
当表中的数据主要通过一个可预测的属性或列访问时,那么把表中的行都聚集在这个特定
的列上可能十分有用。然而,如果该列基于-个人型数据类型,在其上创建聚集索引的存
储和索引维护开销将是非常昂贵的。
3 .包含列
非聚集索引的功能可以通过向索引的叶节点添加非键值得到提升。这就可使索引覆盖
更多的査询,减少为检索额外值而遍历聚集索引的次数。

将索引指派为覆盖索引(covered index)町避免重复遍历聚集索引。 通常,覆盖索引是包含满足査询所需的所有数据的索引。DBA使用的一种方法是在
LastName和 FirstName列上创建非聚集索引。这将把值放在叶节点中的LastName和
FirstName列(因为它们是索引键)以及Contactld列。如果执行一个只需要这3 列的査询, 那么不必遍历聚集索引。这一方法一般情况下都很好,只是索引大小增长过快,因为参与
索引的所有列包含在索引的所有级别中。此外,需要在两列上对索引排序,在更新中这样
做可能会导致性能问题。
包含列(includedcolumn)可以提高査询覆盖率,而不会导致复合索引键的开销。索引中 标记为included的列只出现在索引的叶节点中,在行排序中不作考虑。要在叶节点中包含
列,可使用CREATE INDEX命令的INCLUDE选项。下列命令在LastName列上创建索引, 并包含 AdventureWorks2008 中的 Person.Person 表的 FirstName 列。
CREATE NONCLUSTERED INDEX IX_Person_LastName ON Person.Person(LastName) INCLUDE(FirstName)
4 .筛选索引
筛选索引只是优化的非聚集索引。它允许在数据子集上创建索引,使得索引结构更小,
从而减少了构建索引的时间和索引维护成本。对于包含大量NULL值或包含数据范围(如美
元数)的列上的索引,筛选索引特别有用。要创建筛选索引,只需在CREATE INDEX语句
中包括WHERE子句。下列代码对所有成本大于$800的产品创建索引。
CREATE NONCLUSTERED INDEX IX_ListPrice_Product ON Production.Product(ListPrice) WHERE ListPrice > 800.00;
5 .分层索引
如第4 章所述,Hierarchyld是 SQL Server 2008中引入的一种新数据类型。为了帮助
检索分层数据,可使用两种不同的方法在此类型的列上构建索引:广度优先和深度优先。
广度优先索引
广度优先索引(breadth-first index)将同一级别的所有记录组合在一起。这 样 SQL Server
就可以非常快速地响应具有共同父节点的所有记录的查询。例如,向IT经理作汇报的所有
雇员记录会被组合在一起。下列代码在雇员表上创建一个广度优先索引。
- - Breadth-First IF EXISTS (SELECT * FROM sys.indexes WHERE Name = ,IX_Employee_OrganizationLevel一OrganizationNode’> DROP INDEX IX_Employee_OrganizationLevel_OrganizationNode ON HumanResources.Employee
CREATE NONCLUSTERED INDEX IX_Employee_OrganizationLevel_OrganizationNode ON HumanResources.Employee(


例如,假定我们有一个名为Contacts的表,在其Contactld列上定义了一个聚集索引, 在 其 LastName列上定义了一个非聚集索引。非聚集索引叶节点将包含索引值和聚集键。
当使用LastName作为谓词执行一个需要Contactld、FlrstName和 LastName列的査询时,
LastName上的非聚集索引将用于定位记录,但将只包含两个需要的列,即 LastName和
Contactld。然后,SQL Server必须遍历聚集索引来为找到的每个记录检索F"irstName,值。

猜你喜欢

转载自www.cnblogs.com/zhouwansheng/p/9318678.html