原文:SQL Server :理解数据记录结构

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

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

上图中蓝色部分是所有数据记录部分(即系统行开销,大小基于列个数,等于或大于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)

我们看到数据页号为79。

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

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

在页头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)

我们看到数据页号为202。

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

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

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

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

行头系统数据(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里数据记录的存储格式,希望你已经有了清晰的认识。

SQL Server :理解数据记录结构的更多相关文章

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

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

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

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

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

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

  4. Sql Server删除数据表中重复记录 三种方法

    本文介绍了Sql Server数据库中删除数据表中重复记录的方法. [项目]数据库中users表,包含u_name,u_pwd两个字段,其中u_name存在重复项,现在要实现把重复的项删除![分析]1 ...

  5. SQL Server 变更数据捕获(CDC)监控表数据

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 实现过程(Realization) 补充说明(Addon) 参考文献(References) ...

  6. SQL Server大量数据秒级插入/新增/删除

    原文:SQL Server大量数据秒级插入/新增/删除 1.快速保存,该方法有四个参数,第一个参数为数据库连接,第二个参数为需要保存的DataTable,该参数的TableName属性需要设置为数据库 ...

  7. 数据库迁移(SQL SERVER导入数据到MySql)

    地址:http://blog.csdn.net/jiaohougenyang/article/details/44937801 背景:项目最开始时使用的是SQL Server数据库,业务需求现要将数据 ...

  8. 不同版本的SQL Server之间数据导出导入的方法及性能比较

    原文:不同版本的SQL Server之间数据导出导入的方法及性能比较 工作中有段时间常常涉及到不同版本的数据库间导出导入数据的问题,索性整理一下,并简单比较下性能,有所遗漏的方法也欢迎讨论.补充. 0 ...

  9. 09Microsoft SQL Server 表数据插入,更新,删除

    Microsoft SQL Server 表数据插入,更新,删除 向表中插入数据 INSERT INTO insert into tb1 values(0004,'张凤凤') insert into ...

随机推荐

  1. C语言scanf函数详解

    函数名: scanf  功 能: 运行格式化输入  用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准输入设 ...

  2. Swift - 微调器或叫步进器(UIStepper)的用法

    1,微调器(UIStepper)控件包含两个按钮“+”和“-”,让使用者可以依照自己的喜欢做数值上的调整. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1 ...

  3. 状态压缩动态规划 -- 棋盘问题 POJ 1321

    一个 N * N 的棋盘上面,有些格子不能放,放置 M 的棋子, 每两个棋子不能在同一行或者同一列,问有多少种放法 DFS太慢,用SCR好点点 Python 仅仅有 22 行,事实上能够更短.可是得排 ...

  4. 文件比较,文件夹比较-- vimdiff,beyond compare, compare suite, WinMerge,Kdiff3

    文件比较,文件夹比较-- vimdiff,beyond compare, compare suite, WinMerge,Kdiff3  有一个项目的源码包需要比较,400M以上,这就要找个好的工具了 ...

  5. C语言信号学习笔记

    在C语言中,对于错误有很多处理方式.然而,今天学习了信号处理,感觉这种处理方式十分灵活,特此记录. 关于信号处理的函数包含于头文件<signal.h>中.所谓的信号,多指出乎程序员意料的行 ...

  6. jasperreport报表生成时编译的错误

    在帮徐老板解决一个jasperreport报表生成时编译的错误: 刚开始时,加上他所给的 jar 包之后,错误显示为: net.sf.jasperreports.engine.JRException: ...

  7. zoj 3870

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5518 题意:n个数,从中选出两个数,问这两个数的异或值大于两个数较大 ...

  8. Virtualbox mouse move in and out and file share with windows

    How to use Virstalbox to share files with Linux and Windows, and to move the mouse in and out Virtua ...

  9. Oracle“记录被另一个用户锁住” 无法更新删除的解决办法

    1.查看数据库锁,诊断锁的来源及类型: select object_id,session_id,locked_mode from v$locked_object; 或者用以下命令: select b. ...

  10. SPOJ DISUBSTR(后缀数组)

    传送门:DISUBSTR 题意:给定一个字符串,求不相同的子串. 分析:对于每个sa[i]贡献n-a[i]个后缀,然后减去a[i]与a[i-1]的公共前缀height[i],则每个a[i]贡献n-sa ...