《Microsoft Sql server 2008 Internals》读书笔记订阅地址:
http://www.cnblogs.com/downmoon/category/230397.html/rss
《Microsoft Sql server 2008 Internals》索引目录:
《Microsoft Sql server 2008 Internal》读书笔记--目录索引
前文简要介绍了堆中的非聚集索引行(Nonclustered index rows on a Heap)和聚集表中的非聚集索引行(Nonclustered index rows on a Clustered table)
今天我们继续学习三类特殊的非聚集索引行:
1、非惟一的非聚集索引行(nonunique Nonclustered index rows)
2、使用包含性列的非聚集索引行(nonunique Nonclustered index rows with included Columns(using include))
3、使用筛选器的非聚集索引行(Nonclustered index rows with Filters(Filtered Indexes))
■ 非惟一的非聚集索引行(nonunique Nonclustered index rows)
我们已经知道一个非聚集索引的叶级必须有一个书签,以便于从叶级定位到实际的数据行,而(非聚集索引的)非叶级只需要帮助我们穿越到低级别的叶的pages。一个惟一的非聚集索引(如前例中的主键和惟一的非聚集索引),非叶级行仅仅包含非聚集索引键值和子页指针(Child-Page pointer),然而,如果索引是不惟一的,则非级行包含非聚集索引键值和子页指针和书签值。换句话说,在一个不惟一的、非聚集的索引中,书签值被加到一个非聚集索引键,以确保惟一性(作为书签,在定义时,必须是惟一的)。
记住创建一个索引行的意图:SQL Server并不关心不惟一的索引键是否包含重复值。如果一个索引没有被定义成惟一的,即便所有的非叶级索引行都是惟一的,非叶级索引行总是包含书签。我们可以通过以下三个例子来回顾叶级和非叶级行大小:
ON Employee (SSN);
go
CREATE UNIQUE NONCLUSTERED INDEX TestTreeStructureUnique1
ON Employee (SSN);
go
CREATE UNIQUE NONCLUSTERED INDEX TestTreeStructureUnique2
ON Employee (SSN, EmployeeID);
go
SELECT si.[name] AS iname
, index_depth AS D
, index_level AS L
, record_count AS 'Count'
, page_count AS PgCnt
, avg_page_space_used_in_percent AS 'PgPercentFull'
, min_record_size_in_bytes AS 'MinLen'
, max_record_size_in_bytes AS 'MaxLen'
, avg_record_size_in_bytes AS 'AvgLen'
FROM sys.dm_db_index_physical_stats
(DB_ID ('IndexInternals')
, OBJECT_ID ('IndexInternals.dbo.Employee')
, NULL
, NULL
, 'DETAILED') AS ps
INNER JOIN sys.indexes AS si
ON ps.[object_id] = si.[object_id]
AND ps.[index_id] = si.[index_id]
WHERE ps.[index_id] > 2;
go
注意上图中,索引的叶级(Level 0)都是一样的。第一个索引和第三个索引是相同的。对于第一个索引的EmployeeID被加,是因为它是聚集键(因此作为书签)。第三个索引中EmployeeID已经在索引中,没有被重复添加。然而,在第一个索引中,由于它未被定义成unique,SQL Server不得不添加主键到所有树经过的行。在第二个索引中,因为SSN是惟一的、单独的,因此SQL Server在所有树到之行添加EmployeeID,有兴趣的朋友可以用DBCC IND和DBCC PAGE进一步分析其物理行结构。
■使用包含性列的非聚集索引行(nonunique Nonclustered index rows with included Columns(using include))
到目前为止,对于所有的非聚集索引,我们重点放在索引被约束创建时的物理方面或创建测试物理结构的索引。无论如何,我们必须遵守不能超过900字节或16个列的限制,因为这些限制的存在有助于我们确保索引的可扩展性,但同时它保守地限定了能被用于索引的列最大数。MSDN也有介绍:可以将非键列包含在非聚集索引中,以避免超过当前索引大小的限制(最大键列数为 16,最大索引键大小为 900 字节)。数据库引擎计算索引键列数或索引键大小时,不考虑非键列。请看:
http://msdn.microsoft.com/zh-cn/library/ms190806%28SQL.90%29.aspx
我们也可以查看MSDN:非聚集索引设计指南
http://msdn.microsoft.com/zh-cn/library/ms179325.aspx
在某些情况下,我们需要在一个索引中添加的列允许SQL Server(当访问一个范围查询(range query)时)消除书签查询 ,这就是所谓的覆盖索引(Covering Indexes),这里有关于覆盖索引的介绍:http://en.wikipedia.org/wiki/Index_%28database%29#Covering_Index
一个覆盖索引是一个匹配对应查询的所有信息能够被在叶级查找到的非聚集索引,因此SQL Server根本不需要访问数据页,这在优化复杂的查询时是一个强大的工具,只需要在创建索引时加上include子句即可。参看MSDN:http://msdn.microsoft.com/zh-cn/library/ms188783%28SQL.90%29.aspx
INCLUDE ( column_name [ ,...n ] ) ]。 所有被关键字Include列出的列,允许你在一个非聚集索引的叶级超过900字节或16列的限制,这些包含性列仅仅出现在叶级,对索引行的排序没有任何影响。在某些特定情况下,SQL Server会自动加一个包含性列到你的索引中,(在一个分区给中创建索引而没有使用ON Group或partition_schema_name未被定义时触发)。
■使用筛选器的非聚集索引行(Nonclustered index rows with Filters(Filtered Indexes))
筛选索引是一个非聚集索引的优化形式
http://technet.microsoft.com/en-us/library/cc280372.aspx
如果不使用筛选器,非聚集索引的叶级为表中的每行数据包含一个索引行,逻辑排序由索引所定义。SQL Server 2008中,你可以在创建索引时添加一个筛选谓词,这允许SQL Server仅仅为谓词匹配的行创建非聚集索引行,从而限制了非聚集索引的大小。这在以下情况下非常有用:
1、当一个列包含大多数为Null而查询仅仅需要数据为Not Null。与稀疏列(SPARSE columns)结合时尤其有用。
2、当一个列包含限定数量的感兴趣值或者你想仅仅强化一组值的惟一性。比如,你想允许Employee表的SSN列为Nul值。使用限制,SQL Server允许仅仅单个行为Null,然而,使用筛选索引,你可以创建一个惟一索引在所有SSN为not Null的行。这个语法应该类似:
On Employee(SSN)
WHERE SSN IS NOT NULL
3、当查询检索仅仅在一个特定的范围(range of data),并且你想在这些数据增加索引在,而不是在全表。例如,你有一个表,按月分区,包含了三年地数据(2008,2007,2006)。一个小组想重点分析2007年的第四季度。此时并不需要对所有数据创建一个宽的非聚集索引,只须在创建索引时(也适用于include)关注
使用筛选创建索引的最终结果是非聚集索引的叶级仅仅包含匹配筛选定义的行,筛选定义的列并不一定要在key中,甚至不一定在包含列中,然而,在特定查询中非常有用。
非聚集索引行的相关内容先做个小结,下面我们将学习特定索引结构,了解这几类索引:
Indexes On computered Columns and Indexed View
Full-Text Indexes
Spatial Indexes
XML Indexes