SQL Server 存储(2/8):理解数据记录结构

时间:2022-05-11 08:24:17

SQL Server :理解数据页结构我们提到每条记录都有7 bytes的系统行开销,那这个7 bytes行开销到底是一个什么样的结构,我们一起来看下。

数据记录存储我们具体的数据,换句话说,它存在堆表里,或者存在聚集索引的叶子节点。数据记录结构是为了让SQL Server更高效的管理数据。我们来看下数据记录结构示意图:

SQL Server 存储(2/8):理解数据记录结构

上图中蓝色部分是所有数据记录部分(即系统行开销,大小基于列个数,等于或大于7 bytes),绿色部分是表结构里取决于定长/变长列的数据记录部分(实际存放的数据,大小基于实际数据)。

行头系统数据:

用做状态位1的第1字节(8位)是用来定义记录的属性:

  • 第0位:版本信息,在SQL Server 2008里始终是0;
  • 第1-3位:这3位用来定义记录类型;
    • 0 数据记录(data record)
    • 1 转发记录(Forwarded record)
    • 2 转发存根(a forwarding stub)
    • 3 索引记录(Index record)
    • 4 二进制堆碎片或行溢出数据(blob fragment or row overflow data)
    • 5 鬼影索引记录(ghost index record)
    • 6 鬼影数据记录(ghost data record)
    • 7 鬼影版本记录(ghost version record)
  • 第4位:存在空值位图(Null bitmap )或没有。在SQL Server 2008里没有不为空的列也会有空值位图(Null bitmap );
  • 第5位:表示是否存在变长列;
  • 第6位:表示该列包含版本信息;
  • 第7位:在SQL Server里未使用;

用作状态位2的第2字节(8位)。只有1位用来表示这条记录是否为鬼影转发记录(ghost forwarded record)。

由行头开始到定长列结尾长度:

下2个字节用来存储行头开始到定长列结尾长度。它包含2个状态位,2个字节用作这个列表示在表中定长数据的实际长度。例如如果表里没有定长列,这个列的值会是4。这和页头列pminlen显示的值是一样的。

所有定长列字段值(Fixed_Data_Size):

下n个字节用来存储在表中的定长数据,n就是在表中所有定长列的长度。如果表里的所有列都是变长列,这一部分就没有。

空值位图(Null_Bitmap):

下2个字节用来存储表里的列数。

下n个字节用作空值位图,每个bit对应一个列,1表示对应列为空。n的值为:列数 / 8,将值取整。

Variable_Data_Size:

下2个字节用来存储表里变长列个数。

下n个字节用来存储每个变长列结束为止的偏移量。每个变长列需要2字节,n的值为:变长列数 * 2 。

最后n个字节用来存储所有变长列值,n的值为所有变长列的实际长度的总长度。

我们来看一个具体的例子:

创建数据库,并插入2条记录

 USE [InternalStorageFormat]
GO IF EXISTS ( SELECT *
FROM sysobjects
WHERE id = OBJECT_ID(N'[dbo].[Customers]')
AND OBJECTPROPERTY(id, N'IsUserTable') = 1 )
DROP TABLE dbo.Customers CREATE TABLE Customers
(
FirstName CHAR(50) NOT NULL,
LastName CHAR(50) NOT NULL,
Address CHAR(100) NOT NULL,
ZipCode CHAR(5) NOT NULL,
Rating INT NOT NULL,
ModifiedDate DATETIME NOT NULL,
)
GO INSERT INTO dbo.Customers
( FirstName ,
LastName ,
Address ,
ZipCode ,
Rating ,
ModifiedDate
)
VALUES ( 'Woody' , -- FirstName - char(50)
'Tu' , -- LastName - char(50)
'ZUOQIAO YOUXI TOWN LINHAI CITY' , -- Address - char(50)
'' , -- ZipCode - char(5)
1 , -- Rating - int
'2015-05-07 10:09:51' -- ModifiedDate - datetime
)
go 2

使用DBCC IND命令查看表对应页列表:

 DBCC IND('InternalStorageFormat','Customers',-1)

SQL Server 存储(2/8):理解数据记录结构

我们看到数据页号为79。

使用DBCC PAGE命令查看页信息:

 DBCC TRACEON(3604)
DBCC PAGE(InternalStorageFormat,1,79,3)
GO

SQL Server 存储(2/8):理解数据记录结构

在页头pminlen的值是221,包括定长列的总长217 bytes(50+50+100+5+4+8),2 bytes用作状态位(行头系统开销),2 byte 用作由行头开始到定长列结尾长度。

在记录槽提到的长度224,包括页头pminlen的值,1 byte用作空值位图(6/8 取整为1)和2 bytes 的字段个数。

我们来看一个变长列的表。

创建表并插入数据后,查看表对应的页:

 CREATE TABLE VariableLength(
Title CHAR(10) NOT NULL,
FirstName VARCHAR(100),
Lastname VARCHAR(100),
email VARCHAR(50),
dob date NOT NULL,
phone CHAR(10),
Countrycode CHAR(3),
Designation VARCHAR(100),
PersonalPreference VARCHAR(100)
)
GO
INSERT INTO VariableLength VALUES ('Mr','Woody','Tu','smartgz@qq.com','2015-5-7','XXXXXXXXXX','Chn','DBA','Nothing Spl')
GO
DBCC IND('InternalStorageFormat','VariableLength',-1)

SQL Server 存储(2/8):理解数据记录结构

我们看到数据页号为202。

使用DBCC PAGE命令查看页信息:

 DBCC TRACEON(3604)
GO
DBCC PAGE('InternalStorageFormat',1,202,3)--记得根据你的实际数据库,修改页号202

SQL Server 存储(2/8):理解数据记录结构

pminlen值为30,包含:

  • 1 byte 状态位1
  • 1 byte 状态为2
  • 2 bytes 存储行头开始到定长列结尾长度
  • 26 bytes 所有定长列总长度(10+3+10+3:tittle,dob,phone,countrycode)
    • Title  CHAR(10) NOT NULL

    • dob date NOT NULL

    • phone CHAR(10)

    • Countrycode CHAR(3)

可以用下列语句验证下定长列总长度:

 SELECT DATALENGTH(Title) title,DATALENGTH(dob) dob,DATALENGTH(phone) phone,DATALENGTH(Countrycode) countrycode FROM VariableLength

在槽0显示的81长度包含:

  • 1 byte 状态位1
  • 1 byte 状态为2
  • 2 bytes 存储行头开始到定长列结尾长度
  • 26 bytes 所有定长列总长度(10+3+10+3:tittle,dob,phone,countrycode)
    • Title  CHAR(10) NOT NULL

    • dob date NOT NULL

    • phone CHAR(10)

    • Countrycode CHAR(3)

  • 2 bytes 存储列个数
  • 2 bytes 用作空值位图,字段个数/8后取整,即 9/8 得到2
  • 2 bytes 存储变长列个数
  • 10 bytes 用来存储每个变长列结束位置的偏移量 变长列个数 * 2,即 5 * 2 得到10,5个变长列包含:
    • FirstName VARCHAR(100)

    • Lastname VARCHAR(100)

    • email VARCHAR(50)

    • Designation VARCHAR(100)

    • PersonalPreference VARCHAR(100)

  • 35 bytes 用来存储所有变长列的实际长度,这个可以使用下列语句得到
 SELECT DATALENGTH(FirstName)+DATALENGTH(Lastname)+DATALENGTH(email)+
DATALENGTH(Designation)+DATALENGTH(PersonalPreference) FROM VariableLength

SQL Server 存储(2/8):理解数据记录结构

总结下每条记录的系统行开销:

行头系统数据(2 bytes)+由行头开始到定长列结尾长度(2 bytes)+列个数(2 bytes)+空值位图数据(取整(列个数/8) n bytes)

2 bytes + 2 bytes + 2 bytes + 取整(列个数/8)

当列个数小于等于8时,系统行开销始终是7 bytes,往上没增加8列,增加1 bytes,即系统系统行开销始终大于等于7 bytes

对于在SQL Server里数据记录的存储格式,希望你已经有了清晰的认识。

参考文章:

http://www.sqlservercentral.com/blogs/practicalsqldba/2012/08/22/sql-serverunderstanding-the-data-record-structure/

SQL Server 存储(2/8):理解数据记录结构的更多相关文章

  1. SQL Server :理解数据记录结构

    原文:SQL Server :理解数据记录结构 在SQL Server :理解数据页结构我们提到每条记录都有7 bytes的系统行开销,那这个7 bytes行开销到底是一个什么样的结构,我们一起来看下 ...

  2. sql server数据库查询取出重复数据记录

    问题:博主在2011年6月,广东技术师范大学大四的时候,从学校计算机科学学院网站看到招聘信息并到广东中原地产IT部面试,很清楚记得当时的面试题目:怎么从数据库里面查询重复记录. 解决方案:在sql s ...

  3. SQL Server数据库中导入导出数据及结构时主外键关系的处理

    2015-01-26 软件开发中,经常涉及到不同数据库(包括不同产品的不同版本)之间的数据结构与数据的导入导出.处理过程中会遇到很多问题,尤为突出重要的一个问题就是主从表之间,从表有外检约束,从而导致 ...

  4. SQL Server 存储(1/8):理解数据页结构

    我们都很清楚SQL Server用8KB 的页来存储数据,并且在SQL Server里磁盘 I/O 操作在页级执行.也就是说,SQL Server 读取或写入所有数据页.页有不同的类型,像数据页,GA ...

  5. SQL Server 存储(8/8):理解数据文件结构

    这段时间谈了很多页,现在我们可以看下这些页在数据文件里是如何组织的. 我们都已经知道,SQL Server把数据文件分成8k的页,页是IO的最小操作单位.SQL Server把数据文件里的第1页标记为 ...

  6. SQL Server :理解数据页结构

    原文:SQL Server :理解数据页结构 我们都很清楚SQL Server用8KB 的页来存储数据,并且在SQL Server里磁盘 I/O 操作在页级执行.也就是说,SQL Server 读取或 ...

  7. SQL SERVER存储引擎——04.数据

    4. SQL SERVER存储引擎之数据篇 (4.1)文件 (0)主数据文件.mdf初始文件大小至少为3MB,次要数据文件.ndf初始大小,同日志文件一样至少为512KB: (1)SQL SERVER ...

  8. 腾讯云图片鉴黄集成到C# SQL Server 怎么在分页获取数据的同时获取到总记录数 sqlserver 操作数据表语句模板 .NET MVC后台发送post请求 百度api查询多个地址的经纬度的问题 try{}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会 不会被执行,什么时候被执行,在 return 前还是后? js获取某个日期

    腾讯云图片鉴黄集成到C#   官方文档:https://cloud.tencent.com/document/product/641/12422 请求官方API及签名的生成代码如下: public c ...

  9. SQL Server 存储字符数较大字段的问题

    SQL Server 2000专门提供了处理text,ntext,image字段的函数,他们是: TEXTPTR TEXTVALID READTEXT UPDATETEXT WRITETEXT 一般作 ...

随机推荐

  1. Extjs 下拉框显示远程数据

    var store = new HT.SyncStore({ baseParams : { itemName : '绩效考核_任务状态' }, url : __ctxPath + '/system/l ...

  2. Google Protocol Buffer开发环境搭建注意事项

    PB的安装配置基本上依照网上的教程做就没什么问题:有一点要注意到是当遇到libcmt.lib或msvcrt.lib等lib库与PB中的库冲突时,一定要检查工程的编译方式完全一致,整个项目当中都要注意这 ...

  3. 如何在Android studio中同时打开多个工程? (转载)

    最近学习Android Studio,想同时打开两个Project.但是点击File->Open之后,原有的Project被关闭掉了.怎么在新的窗口中打开Project呢? 解决: 点击Help ...

  4. 一天搞定HTML----标签语义化04

    根据页面里不同的内容,选择最适合它的标签,而不通篇只用一种标签 标签语义化作用: 代码演示 通过比较- - -H5布局和DIV+CSS 布局- - -体现标签语义化 注意: 标签语义化,不仅仅只是指使 ...

  5. Presto0.157版本单节点部署教程

    因为Presto版本的更新速度较快,所以最好按照对应版本的教程进行部署,博主之前看错了版本号,拿0.100版本的教程来部署0.157版本,结果导致部署失败. 官网:https://prestodb.i ...

  6. 在windows下,将mysql离线数据文件导入本地mysql数据库

    1. 查看mysql路径 SELECT @@basedir AS basePath FROM DUAL 其实mysql5.6 的数据文件在 C:\ProgramData\MySQL\MySQL Ser ...

  7. SpringMVC 表单验证

    SpringMVC 表单验证 本章节内容很丰富,主要有基本的表单操作,数据的格式化,数据的校验,以及提示信息的国际化等实用技能. 首先看效果图 项目结构图 接下来用代码重点学习SpringMVC的表单 ...

  8. java基础梳理--朝花夕拾(一)

    简介: Java是一种撰写跨平台应用软件的面向对象语言,1995年由Sun Microsystems公司推出. 2009年04月20日,甲骨文74亿美元收购Sun,取得java的版权. 2011年7月 ...

  9. Deep Learning Tutorial - Multilayer perceptron

    Multilayer perceptron:多层感知器 本节实现两层网络(一个隐层)作为分类器实现手写数字分类.引入的内容:激活函数(双曲正切.L1和L2正则化).Theano的共享变量.grad.f ...

  10. windbg 经典死锁调试

    代码 // Deadlock_Debug.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include "windows.h& ...