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

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介:
20151223101035504.jpg
 

 

 

目录

 

  • 什么时候触发行溢出

  • 行溢出的存储结构

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

  • 总结

 

 

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

 

1 什么时候触发行溢出

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

 

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

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

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

2 行溢出的存储结构

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

 

20160801054429171.png

 

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

20160801054437749.png


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

20160801054457328.jpg

图1:堆表HeapPage_Overflow记录结构

 

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

 

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

 

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

 

 

20160801054514386.jpg

图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的内容:
20160801054534668.png

 

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

20160801054559503.jpg

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

 

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

 

20160801054609923.jpg

图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 行溢出的整体逻辑结构图

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

 

20160801054635362.jpg

图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

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
20天前
|
存储 算法 NoSQL
什么是数组存储结构
什么是数组存储结构
50 8
|
20天前
|
存储 开发工具
栈存储结构详解
栈存储结构详解
42 7
|
3月前
|
设计模式 算法 Java
【数据结构和算法】最大连续1的个数 III
这是力扣的 1004 题,难度为中等,解题方案有很多种,本文讲解我认为最奇妙的一种。又是一道滑动窗口的典型例题,可以帮助我们巩固滑动窗口算法。这道题很活灵活现,需要加深对题意的变相理解。给定一个二进制数组nums和一个整数k,如果可以翻转最多k个0,则返回数组中连续1的最大个数。
64 2
|
4月前
|
存储 C语言
【数据结构】顺序表的定义和运算
【数据结构】顺序表的定义和运算
64 0
|
6月前
|
存储 算法 安全
数据结构 - 6(优先级队列(堆)13000字详解)
数据结构 - 6(优先级队列(堆)13000字详解)
24 0
|
3月前
|
存储 算法
数据结构——堆(存储完全二叉树)
数据结构——堆(存储完全二叉树)
24 0
|
3月前
|
存储 算法
数据结构(数组、链表、栈、队列、树)(二)
数据结构(数组、链表、栈、队列、树)(二)
|
3月前
|
存储 Java 索引
数据结构(数组、链表、栈、队列、树)(一)
数据结构(数组、链表、栈、队列、树)
|
6月前
|
存储 设计模式 安全
数据结构 - 2(顺序表10000字详解)
数据结构 - 2(顺序表10000字详解)
23 0
|
6月前
|
存储 Java 容器
数据结构 - 3(链表12000字详解)
数据结构 - 3(链表12000字详解)
31 0