深入剖析行溢出的存储结构

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
简介:
 

 

 

目录

 

  • 什么时候触发行溢出

  • 行溢出的存储结构

  • 行溢出的整体逻辑结构图

  • 总结

 

 

本文以SQL Server为例聊聊行溢出的存储结构

 

1
什么时候触发行溢出

SQL Server的行溢出数据只会发生在变长字段上,变长列的长度不能超过标准变长列最大值8000个字节的限制,而且还要满足:

 

  • 包括行头系统信息和所有定长列和变长系统信息的所有长度不能超过8060字节,要想存储8000字节以上的数据,应该使用LOB(text、ntext或者image)或者MAX数据类型;

  • 变长列的实际长度一定要超过24个字节(因为行溢出需要额外的24个字节行溢出指针,如果变长字段值不超过24个字节,完全没有必要把它作为行溢出数据存储);

  • 变长列不能是聚集索引键的一部分(如果行溢出是聚集索引键的一部分,那么表的查询性能会是一个噩梦);

2
行溢出的存储结构

为了了解Overflow的结构,我们创建表HeapPage_Overflow,并插入测试数据:

 

 

查看这行记录对于Page的内容:


上面Page数据中的一行记录可以格式化为下图所示:

图1:堆表HeapPage_Overflow记录结构

 

其中几个重要部分结构解释如下:

 

  • 0x2980这是包含后面指向存储行溢出的变长字段偏移量。把0x2980逆序成0x8029,再把0x8029转换为二进制1000000000101001,去除高2位(也就是粗体部分),取101001,转换为十进制就是41,高2位的目的其实只是一个标识,为了跟普通记录的变长字段偏移量进行区分。

 

  • 第一个变长字段偏移量41是由17个字节系统信息加上24个字节的行溢出指针共同组成,计算公式为:41=17+24,下面对这24个字节的行溢出指针进行结构分析:

 

 

图2:堆表HeapPage_Overflow的行溢出指针结构

 

 

  • 0x02,特殊字段的类型,0x02表示行溢出数据;

  • 0x0000,表示B树中的层级,行溢出的记录,这个值为始终为0,在LOB记录的ROOT记录中这个值为0x0100;

  • 0x00,暂时未使用;

  • 0x01000000,一个序列号,每次行溢出或LOB数据被更新时这个值加1,并在乐观并发控制为游标使用;

  • 0x804A0000,Timestamp值,用于使用DBCC CHECKTABLE检查表索引、行内、LOB 以及行溢出数据页是否已正确链接。在LOB的行内数据、LOB的ROOT指针以及存储LOB的数据结构中都存储了这个值,而且他们的值都是一样的。0x804A0000逆序之后是0x0004A80,再向0x0004A80后面追加4个0得到0x0004A800000,转换为十进制为1249902592;要验证这个标识值的算法,可以使用工具Winhex修改0x804A0000值并使用DBCC PAGE(Overflow,1,93,3) 查看Timestamp值。

  • 0x70170000,溢出字段长度,0x70170000逆序之后是0x00001770,用十进制表示是6000,这个跟前面插入记录时字段的大小完全吻合;

  • 0x5900000001000000表示一个8个字节的RID地址,指向行溢出字段VarCol存储6000字节所在数据页的RID地址为:(1:89:0)。

 

上面已经分析了在行内数据中存储的行溢出指针的结构,接下来将分析存储行溢出数据的物理结构。

 

查看行溢出存储Page的内容:

 

上面Page数据中的一行记录可以格式化为下图所示:

图3:堆表HeapPage_Overflow的行溢出数据结构

 

  • 0x0800是这一行记录的行头数据,分解为Byte#0的十六进制是0x08和Byte#1的十六进制是0x00,0x08转换为二进制是:00001000,各个bit表示的含义如下:

 

图4:堆表HeapPage_Overflow的行溢出行头结构

 

 

  • 0x7E17是变长偏移量,经过逆序之后是0x177E,用十进制表示是6014,这个偏移量包含了14个字节的行溢出系统数据和6000个字节的行溢出字段值;

  • 0x0000804A00000000是Blob Id值,跟IN_ROW_DATA记录中24个字节的行溢出指针的Timestamp值是相等的。要验证这个标识值的算法,可以使用工具Winhex修改0x0000804A00000000的值并使用DBCC PAGE(Overflow,1,89,3)查看这个Blob Id值。如果不相等,虽然SELECT一样能查询数据,但是在进行DBCC CHECKDB将会报引用不匹配的错误信息。

  • 0x0300是数据类型,转换为十进制是3,Type=3表示DATA,即表示这行记录是用于存储数据的。

3
行溢出的整体逻辑结构图

根据上面对行记录存储结构的分析,行溢出的逻辑可以通过下面的图来表示:

 

图5:堆表HeapPage_Forward第一行记录行溢出后的存储结构示意图

4
总结

上文以堆表的行溢出数据为例讲解它的存储结构,从结构来看一行记录的存储跨越了两个Page,相比于一条记录存储在一个Page里,查询的时候增加了1个IO,当表比较大的时候,随机IO将会猛增,将会出现性能上的问题,一般建议控制好变长字段的大小,或者使用其它数据类型避免行溢出,也可以考虑表的垂直拆分。

更多关于SQL Server存储结构请参考《SQL Server性能调优实战》

 

 

作者介绍:陈畅亮

 

  • 【DBA+社群】广州联合发起人

  • 微软SQL Server方向最有价值专家(MVP),《SQL Server性能调优实战》作者,《Windows PowerShell实战指南(第2版)》译者。

  • 主要研究MySQL、SQL Server、NoSQL,以及分布式环境下海量数据存储的设计与开发。

  • 2015年DTCC大会演讲嘉宾


本文来自云栖社区合作伙伴"DBAplus",原文发布时间:2015-12-23

目录
相关文章
|
Kubernetes Cloud Native 应用服务中间件
云原生|kubernetes|kubernetes集群使用私有镜像仓库拉取镜像(harbor或者官方的registry私有镜像仓库)
云原生|kubernetes|kubernetes集群使用私有镜像仓库拉取镜像(harbor或者官方的registry私有镜像仓库)
1909 0
|
C语言
【51单片机】LCD1602显示字符串,时间、时间+按键校准、秒表计时的功能代码。
【51单片机】LCD1602显示字符串,时间、时间+按键校准、秒表计时的功能代码。
316 3
|
7月前
|
数据采集 缓存 搜索推荐
NewsNow:开源个性化新闻聚合平台
NewsNow是一个功能强大且易于上手的新闻聚合项目,通过简单的部署步骤,你就可以拥有一个属于自己的个性化新闻聚合平台。无论是学习TypeScript、了解Web开发,还是打造专属的新闻阅读工具,NewsNow都是一个不错的选择。
369 2
NewsNow:开源个性化新闻聚合平台
|
7月前
|
机器学习/深度学习 人工智能 运维
机器学习+自动化运维:让服务器自己修Bug,运维变轻松!
机器学习+自动化运维:让服务器自己修Bug,运维变轻松!
285 14
|
小程序 Java 编译器
性能工具之JMeter 微信小程序 WebSocket 脚本入门
【5月更文挑战第12天】性能工具之JMeter 微信小程序 WebSocket 脚本入门
404 1
|
消息中间件 物联网 网络性能优化
MQTT常见问题之MQTT的topic超出上限25个如何解决
MQTT(Message Queuing Telemetry Transport)是一个轻量级的、基于发布/订阅模式的消息协议,广泛用于物联网(IoT)中设备间的通信。以下是MQTT使用过程中可能遇到的一些常见问题及其答案的汇总:
|
域名解析 移动开发 运维
Nacos 集群部署模式最佳实践
本文介绍了 Nacos 的三种部署模式,并就高可用、可伸缩、易用性等方面对各个模式进行介绍。
13244 105
Nacos 集群部署模式最佳实践
|
C语言
C语言:二进制、八进制、十六进制整数的书写及输出
C语言:二进制、八进制、十六进制整数的书写及输出
|
弹性计算 安全 Windows
Internet Information Services(IIS)部署Web项目
Window Server2016服务器,mstsc远程桌面连接,IIS安装与配置
990 0
Internet Information Services(IIS)部署Web项目