虽然在SQL Server中名义上有两种类型的索引(聚集索引和非聚集索引),但实际上,内部来说有3种索引类型,分别是 聚集索引,非聚集索引其中包含堆上的非聚集所以,聚集索引上的非聚集索引。
物理数据的存储方式在聚集索引和非聚集索引之间有所不同。SQL Server遍历B树到达最终数据的方式在3种索引类型之间各不相同。
所有SQL Server索引都有叶级页和非叶级页。叶级页和非叶级页。叶级是保存标识记录的“键”的,非叶级是引到到叶级的。
索引要么构建在聚集表(有聚集索引的表)上,要么构建在堆(没有聚集索引的表)上。
提示:你可能会产生这样的疑问,“如果聚集索引不是唯一的,将会怎样呢?”既是说,如果聚集索引不是唯一索引,怎样才能用聚集索引唯一标识一行呢?答案是隐蔽的:SQL Server强制所有的聚集索引唯一,即使没有把聚集索引定义成唯一的,也是如此。幸运的是,它强制索引唯一的方式不会改变索引的使用方式。如果你愿意,仍然可以插入重复的行,只是SQL Server 会在内部为键添加后缀,以确保该行具有唯一的标识符。
堆是任何没有聚集索引的表。这种情况下,将基于该行的区段、页和行偏移量(从页首到该行的距离)的组合来创建唯一标识符或行ID.只有当没有聚集键可用时(没有聚集索引),RID才是必须的。
1聚集索引对任何指定的表来说,聚集索引是唯一的——每个表只能有一个聚集索引。并非一定要有聚集索引。但是,你会发现它是最经常作为第一个索引选用的索引类型,由于各种各样的原因,查看索引类的时候,那会是非常明显的。
聚集索引的特殊之处在于,它的叶级是真正的数据——即数据按照索引或相关键命令中定义的物理顺序进行排序存储。这意味着,一旦到达索引的叶级,就到达了终点——这里是真正的数据。新纪录根据它在聚集索引里正确的物理顺序进行插入。创建新页的方式会随着需要插入记录的位置的变化而变化。
当新纪录必须插入到索引结构中间时,会发生常规的页拆分。来自原来页中后半部分的记录被移动到新页上,新纪录适当地插入到新的或旧的页中。
当新纪录在逻辑上位于索引结构的末尾时,将创建一个新页。但是只有新纪录添加到新页中,如图所示。
在数中导航SQL Server中的索引以B树结构存储。在理论上,在B树分叉的每一个方向上,总是有一半的剩余信息。下面来看一下聚集索引的B树图示
可以看出,它实际上与一般的B树是一样的。在这里进行的是范围搜索(有时聚集索引尤其擅长此类事情)。搜索158—400的数字,只需要按照如下步骤进行:导航到第一条记录,并包含该页中所有的其余记录(之所以知道需要该页中其余的记录,是因为我们从上一级节点的信息中得到还需要来自其它页中的数据。因为这是一个有序的列表,所哟可以确定它是连续的),这意味着如果下一页中有需要包含进来的记录,那么本页中其余的记录必定都要包含进来。我们可以开始从这些页中提取记录,而不需要完成确认方面的工作。我们从导航节点开始。SQL Server可以基于一个保存为系统表的条目定位跟节点。可以通过查询sys.indexes查看那个表的逻辑内容。
注意:数据库中的每一个索引在sys.indexes中都有一个条目。系统视图是数据库的一部分(与主数据库中相反)而且会显示数据库中所有索引的存储位置信息,以及它们基于那个列。在版本较旧的SQL Server中。可以查询基础表(在技术上你可以这么做,不过本人强烈推荐你不要直接查询),即所谓的sysindexes表。
浏览作为根节点的页,可以知道接下来要检查的页是什么(正如图中所显示,我们要查看第二级的第二页)。然后,继续处理。随着我们沿着树一步步向下,将得到越来越小的数据子集。最终,我们会到达索引级别的叶级。在聚集索引中,到达索引的叶级意味这也到达了要找寻的行和要找寻的数据。
注意:关于区别重要性,我已经强调过很多了。有了聚集索引,在完整浏览索引的时候就已经完整地浏览了自己的数据。早你观察非聚集索引的时候会发现这样做对性能的影响差别有多大——特别是在聚集索引上建立非聚集索引的时候。
2堆上的非聚集索引堆上的非聚集索引在各方面都与聚集索引的作用方式很类似。不过它们确实有几个显著的区别:叶级不是数据,而是你可以获得数据指针的级别。指针以索引指向的特定行的行标识符(RID)的形式出现,对于RID大家都应该有所了解,它由索引指向特定行的区段、页和行偏移量组成。尽管叶级并非真正的数据(而是具有RID)。不过,这里只比使用聚集索引多了一步而已——因为RID包含行位置的完整信息,因而可以直接访问数据。