值得说明的是,上面的图只是一个样子,正常的情况下一个页中会包含远多于上面例子的行,并且页也会远远多于上面的例子。

  实际在页中索引条目并不是有序的,而是靠偏移指针进行定位的,这个页尾的偏移表是有序的。

  很多情况下,页中并不像上面图中所展现的那样,页之间物理上是连续的,但它们之间逻辑上是连续的,逻辑和物理上的差异被称之为碎片。

  正如我们之前所说,每一个索引可以包含不止一层的中间页。

  继续使用我们之前电话本的类比。比如你查找名为Helen Meyer的联系人,打开电话本找到第一页,对于在区间 “Fernandez, Zelda”和 “Olsen, Karl”之间的名字,去看页5:431.然后你找到431页,这页告诉你对于Kumar, Kevin”和“Nara, Alison”之间的名字,去找页5:2006。然后你找到5:2006找到了你所需的联系人。

  索引深度

  索引的根页以及相关信息是存在系统表中的。每当SQL Server进行页查找时,SQL Server都会从根页开始查找,经过中间节点,直到找到叶子节点,然后从叶子中找到需要的索引条目。对于我们10亿行的表来说,从根节点到叶子节点共需要读取5层。而对图1所示的节点来说,只需要读取3次IO。

  上面所说的层数,也被成为索引深度。取决于索引键的大小和数量。在AdventureWorks示例数据库中,没有哪个索引的层级超过3层。但对于其它索引键宽或是数据量大的表,会有更深的层级。

  sys.dm_db_index_physical_stats函数可以展示索引的详细信息,深度和大小。这是一个表值函数,比如下面代码我们可以找到SalesOrderDetai表相关的索引信息。

 

SELECT  OBJECT_NAME(P.OBJECT_ID) AS 'Table' ,
        I.name AS 'Index' ,
        P.index_id AS 'IndexID' ,
        P.index_type_desc ,
        P.index_depth ,
        P.page_count
FROM    sys.dm_db_index_physical_stats(DB_ID(),
                                       OBJECT_ID('Sales.SalesOrderDetail'),
                                       NULL, NULL, NULL) P         JOIN
sys.indexes I ON I.OBJECT_ID = P.OBJECT_ID
                              AND I.index_id = P.index_id ;

  得到的结果如图2所示。

图2.查询sys.dm_db_index_physical_stats函数得到的结果

通过如下代码我们可以看到更详细的层级信息

 

SELECT  OBJECT_NAME(P.OBJECT_ID) AS 'Table' ,
        I.name AS 'Index' ,
        P.index_id AS 'IndexID' ,
        P.index_type_desc ,
        P.index_level ,
        P.page_count
FROM    sys.dm_db_index_physical_stats(DB_ID(),
                                       OBJECT_ID('Sales.SalesOrderDetail'), 2,
                                       NULL, 'DETAILED') P         JOIN
sys.indexes I ON I.OBJECT_ID = P.OBJECT_ID
                              AND I.index_id = P.index_id ;