您的位置:首页 > 数据库

索引的结构-SQL Server

2016-07-06 00:19 204 查看
索引使数据以一种特定的方式组织起来,从而可以提供对数据的快速访问。

表和索引的结构

页和分区

是SQL Server存储数据的基本单位,大小为8 KB。它可以包含表数据或索引数据,执行计划数据,分配位图,可用空间信息等。页是SQL Server可以读写的最小I/O单位。即使只访问一行,它也把整个页加载到缓存并从缓存中读取数据。涉及数据查询操作的开销通常是I/O开销。显然,物理地读取一页比从缓存中逻辑地读取一页所产生的开销要大得多。

是8个连续页组成的分配单元。当表或索引需要更多空间以存储数据时,SQL Server为该对象分配一个完整的区。但有一个例外:如果该对象不足64
KB(8*8 KB(页)),则当需要更多空间时,SQL Server通常只为该对象分配一个完整的页,而不是整个区。该页可以位于一个混合区内,混合区内的8个页属于不同的对象。

I/O操作中最大开销是磁臂的移动,而实际的磁读和磁写操作的开销要小得多,因此读取一个页几乎和读取整个区所用的时间一样。

堆是不含聚集索引的表。这种结构之所以被称为堆是因为它的数据不按任何顺序存储。

联系一个堆中的数据的唯一结构是被称为索引分配映射(Index Allocation Map ,IAM)的一个位图页(如果需要,可能是多个IAM页)。该位图页包含指向在混合区(mixed extent)分配的前八个页的指针,还包含一个大位图,每个位表示文件中4
G范围内的一个区,如果一个区不属于拥有该IAM页的对象,则标记为0,否则为1。如果一个IAM不足以覆盖该对象的所有数据,SQL Server将维护一个IAM页的链。当扫描对象时,使用IAM页遍历该对象的数据。SQL Server加载该对象的第一个IAM页,然后指示磁臂按区在磁盘上的物理顺序连续地访问他们。

SQL Server维护指向第一个IAM页和堆中第一个数据页的内部指针。



聚集索引

SQL Server中所有索引都是按B+树的结构来组织的。

聚集索引是按B+树的结构来组织的,聚集索引在叶级表中维护所有的数据。聚集索引不是该数据的副本,而是数据本身。



我们把具有聚集索引的表称为聚集表。表的完整数据行按索引键的顺序存储在索引的叶级。有一个双向链接列表用于维护这种逻辑顺序。但要注意,根据索引的碎片级别,磁盘上页的物理顺序可能和链接列表维护的逻辑顺序不匹配。

还要注意,对于每个叶级行(元组),索引维护一个唯一标识符(unq)。该值列举具有相同键值(key value)的行,当索引的键列不唯一时,该值和键值共同唯一的标识行。

当SQL Server需要在索引的叶级别执行有序扫描(或有序局部扫描)操作时,将按链接列表进行扫描。除了链接列表,SQL server还维护一个(或多个)IAM页以映射在磁盘上按物理顺序存储的数据。当SQL Server需要无序扫描索引的叶级别时,通常使用IAM页。有序和无序扫描的性能差异取决于索引的碎片级别。I/0操作中成本最高的部分是磁臂的移动。在没有碎片的索引中执行有序扫描与无序扫描的性能相差无几,但如果索引的碎片级别较高,则有序扫描要慢得多。

在索引叶级别的上层,索引还维护其他的级别,每个级别都概括了它下面的级别。非叶级索引页中的每一行指向它下一级别的整个页。该行包括两个元素:被指向索引页的第一行的键值,以及一个6字节的指针,该指针包括数据库的文件号和文件中的页号。当SQL server生成索引时,它从叶级别开始,向上添加级别。当一个级别只有一个页时停止,而该页被称为根页(root page)。

当SQL Server需要导航到位于叶级的特定键时,它总是从根页开始,并使用被称为索引查找(index seek)的访问方法。查找操作将从根“跳”到下一级别的相应页,并继续从一个级别跳到下一个级别,直到达到包含被查找键的叶级页。所有叶级页到达根的距离都是相同的,这意味着一次查找操作在页读取(page reads)方面的成本正好是索引的级数。这种读取操作的I/O模式不是连续的I/0,而是随机的I/O,因为查找操作所读取的页很少相邻。

在性能估计时,知道一个索引的级数是非常重要的,因为这个数正好是一次查找操作在页读取方面的成本。一般而言,对于小表,大多数索引通常只有两级。对于大表(百万级),通常包含3级或4级。相对于聚集索引,非聚集索在它的叶级页可以容纳更多的行,所以相同级数的非聚集索引可以包含更多的行。因为非聚集索引的叶级行仅包含索引键列和指向特定数据行的行定位符。

非聚集索引

非聚集索引也是按B+树的结构来组织的,而且在许多方面都和聚集索引类似。唯一区别是非聚集索引的叶级行仅包含索引键列和指向特定数据行的行定位符。行定位符的内容取决于该表是一个堆还是一个聚集表。

堆上的非聚集索引

非聚集索引的叶级行中指向数据行的行定位符是一个8字节的物理指针,被称为RID。它由数据库文件号,文件中的目标页号,目标页中的行号(从0开始)组成。当通过索引查找到特定行时,SQL
Server必须在查找操作后执行RID lookup操作,该操作用于读取包含数据行的页。因此,RID lookup的成本是一个页读取。

对于一次lookup或者少量lookup,它的成本并不高,但是对于大量的lookup来说,它的成本会非常高,因为SQL Server需要为找到的每个行读取页。对于使用非聚集索引的范围查询,以及一批lookup(每次符合条件的行一次lookup),lookup操作的累计成本通常构成了查询的大部分成本。



聚集表上的非聚集索引

与堆上的非聚集索引唯一的区别是:在聚集表上创建的非聚集索引的行定位符是一个被称为聚集键的值,而不是RID。聚集键由目标行的聚集索引值和唯一标识符组成。其原理是指向逻辑的行,而不是物理的行。

这种架构主要是为OLTP(联机事务处理)系统而设计的,在这种系统下,当插入数据时聚集索引常常出现大量的页拆分。当被拆分的页中,有一半的行会被物理地移动到新分配的页。如果非聚集索引保存指向行的物理地址,所有指向这些被移动数据行的指针必须被更改以反映新的物理位置,而且对于所有非聚集索引中的相关指针也都要被更新。如果SQL Server维护逻辑指针,则物理地移动数据行时,非聚集索引上的这些指针不需要被更新。

查找操作在非聚集索引中查找特定键,最后到达相应的叶级行并访问行定位符。这种情况下的行定位符是被指向行的聚集键,lookup操作将在聚集索引内根据得到的聚集键执行完整的查找操作。其中每次lookup操作的成本(读取页数方面)与聚集索引的级数一样高。而当表是一个堆时,RID lookup的成本只是一个页读取(page read)。当然,对于使用非聚集索引的范围查询和一系列lookup,在堆和聚集索引表中逻辑读取数之间的比例接近于L,其中L是聚集索引的级数。

在你对此感到困惑并移除所有聚集索引之前,记住,对聚集索引执行lookup操作时,聚集索引的非叶级页通常都已经在缓存中了。通常,大多数聚集索引的物理读取是发生在叶级的。因此对聚集表的额外lookup成本相对于堆来说只占总查询成本的一小部分。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: