失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > SQL Server存储结构之聚集索引

SQL Server存储结构之聚集索引

时间:2023-12-14 15:59:28

相关推荐

SQL Server存储结构之聚集索引

聚集索引即基于数据行的键值在表内排序和存储这些数据行。每个表只能有一个聚集索引,因为数据行本身只能按一个顺序存储。

从某种程度上,聚集索引即数据,这句话是有道理的;但正如同其他索引一样,聚集索引也是按 B 树结构进行组织的。既然是B树组织,那么就有叶子结点和非叶子节点之分。聚集索引B 树的顶端节点称为根节点;聚集索引中的底层节点称为叶节点。在根节点与叶节点之间的任何索引级别统称为中间级。在聚集索引中,叶节点包含基础表的数据页。根节点和中间级节点包含存有索引行的索引页。每个索引行包含一个键值和一个指针,该指针指向 B 树上的某一中间级页或叶级索引中的某个数据行。每级索引中的页均被链接在双向链接列表中。

因此可以这么说,聚集索引的叶子结点存储的是按聚集索引顺序排列的数据本身,而中间结点和根节点则在维护索引和其层级。

对于某个聚集索引, sys.system_internals_allocation_units 中的 root_page 列指向该聚集索引某个特定分区的顶部。SQL Server 将从索引中向下移动以查找与某个聚集索引键对应的行。为了查找键的范围,SQL Server 将在索引中移动以查找该范围的起始键值,然后用向前或向后指针在数据页中进行扫描。为了查找数据页链的首页,SQL Server 将从索引的根节点沿最左边的指针进行扫描。

下面我们用dbcc命令介绍一下聚集索引的构造。

其中红颜色的部分为每行的行头部分,蓝颜色部分为每行的结尾部分。

大家可以看到m_type=1即数据页面,大家应该很奇怪吧,为什么明明是聚集索引,却是数据页面呢?正如上面所提到,聚集索引的叶子页面即数据页面。因为这个表只有2~3条记录,所以root页面还达不到需要分为B树的程度,所以该root页面也是叶子页面。

我们首先来看一下1000d407的行头部如何解释

即该行为不存在变长字段的主记录,且字段长度为个字节。

那30 00d407该如何解释呢?即00001100即存在变长字段的主记录,我们的testNonUniqueCluster怎么会存在变长字段呢?

在该非唯一聚集索引表中,我们首先插入记录B、BBB2记录,再插入B、BBB1记录,这个时候对于非唯一索引如何去识别呢?SQL Server在重复行的行尾增加了8个额外的字节,稍后我们再分析行尾。

在testUniqueCluster表中正常的行尾为0200fc,其解释如下0200表示该表有2个字段,fc则为1111 1100,即前2个字段不为空。

而对于testNonUniqueCluster表正常的行尾应为0300 f8,其解释如下0300表示该表有3个字段,f8则为1111 1000,即前3个字段不为空;很显然SQL Server把非唯一索引的标识符也当做字段了;但的的确确因为B、BBB2和A、AAA1在插入的时候是唯一的,所以不需要这个字段。

我们接下来看看B、BBB1行的尾部03 00f8 0100 df070100 0000,0300f8解释同上,0100即1表示该表一共有1个变长字段,df07即变长字段结束的位置,最后四个字节0100 0000为非唯一索引的标识符,换算成10进制即1。

从页面中记录的顺序我们其实可以看得出来,聚集索引的行的物理顺序与行的实际存储没有太大关系,而是与记录槽的顺序的有关。

既然我们再谈论聚集索引,那就不能不说聚集索引的中间节点和根节点了,

为了简化处理,我们使用testUniqueCluster来做进一步的研究。

该表包含2个定长字段,合计2000字节,加上相应的头部的4个管理字节和尾部的3个管理字节,共计个字节,页头还需要96个字节,每行的偏移量需要2个字节,所以单页8192字节只能容纳大概4条记录。也就是说当我们完成第五条记录时就应该产生分页现象了。

以下为该表的详细页面分布

我们再用sys.system_internals_allocation_units来看一下该表的页面概要信息。

从以上两个表格,我们可以看出IAM页面未发生变化,仍旧是第234页面。

根节点页面发生了变化,现在是第239页面,pagetype=2,即索引页面,新增加了一个数据页面第248页面,第233页面仍继续存在;同时在第248和233个页面之间存在着互链的关系。

同时观察一下数据,发现在第233页中存在A、AAA1;B、BBB1;C、CCC1;D、DDD1等4条记录,而第248页中则存在E、EEE1记录,也就是说对于SQL Server来说索引的分裂应该是以最小代价进行,而不是完全均衡策略。

再让我们用DBCC PAGE(1,testDB,239,3)观察一下根节点的内容。

因为这是个索引的非叶子节点,所以连表现形式都简化了。

FieldId为当前页面的文件ID

PageId为当前页面的页面ID

Row表示为当前的slot槽

Level为1表示为当前为非叶子节点

ChildFieldId表示为插槽号指向的页面的文件ID

ChildPageId表示为插槽号指向的页面的页面ID

Name表示为当前索引的键值

KeyHashValue为SQL Server键值的内部表示的hash值。

即E右侧的数据指向第248页面,而左侧的则指向第233页面。

那么再让我们插入4条记录看看根页面的变化。

现在我们可以看到在根节点上又增加了一个新的键值I,凡是大于等于I的记录均指向第249页;结合前面的描述,我们可以得到下面的索引结构变化示意图。

如果觉得《SQL Server存储结构之聚集索引》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。