数据库之数据行结构(SQL Server )
感觉关于数据库的 数据行结构
(data row/record structure) 这方面的内容国内的资料特别少,老师上课讲到后,怎么搜也搜不到,最后还是爬梯|=|子才搜到一些的(国内真的惨),这里对老师上课讲的和网上看的做一个小总结,加深印象。
数据行结构
行结构总览
SQL Server系统 数据类型可以在逻辑上分为两个不同的组,例如固定长度(fixed-length)和可变长度(variable-length)类型。 固定长度数据类型(如int,datetime,char等)始终使用相同的存储空间,无论值是什么,即使它是NULL。 例如,int列始终使用4个字节,nchar(10)列始终使用20个字节来存储信息。
相反,可变长度数据类型(例如varchar,varbinary和其他一些数据类型)使用尽可能多的存储空间来存储数据加上两个额外字节。 例如,nvarchar(4000)列将仅使用12个字节来存储5个字符的字符串,并且在大多数情况下,2个字节用于存储NULL值。 我们将讨论可变长度列以后不为NULL值使用存储空间的情况。
下面是两张关于 SQL Server 里数据行结构的图,其中一张来自http://aboutsqlserver.com/2013/10/15/sql-server-storage-engine-data-pages-and-data-rows/:
该行的前2个字节(称为状态位A(Status Bits A)和状态位B(Status Bits B))是包含有关该行的信息的位图,例如行类型是什么; 该行是否已被逻辑删除(幽灵(ghosted)); 该行是否具有NULL值,可变长度列和版本控制标记。
行中接下来的两个字节用于存储数据的固定长度(fixed-length)部分的长度。 它们之后是固定长度的数据(fixed-length data)。
在固定长度数据部分之后,存在空位图(null bitmap),其包括两个不同的数据元素。 第一个2字节元素是行中的列数(number of columns)。 接下来是空位图数组(null bitmap array),该数组使用一位来表示表中的每一列,无论它是否可为空。
ps. 原文中的 它 有点不明白代指什么。因为使用一位来表示一列,所以共有 Ceiling(#cols / 8)
个字节
即使表没有可空列,空位图也始终存在于堆表或聚簇索引叶行的数据行中。但是,当索引中没有可为空的列时,非页索引行中的空位图不存在,也不存在非聚簇索引的叶级行。
在空位图之后,是该行的可变长度数据(variable-length data)部分。 它从行中的两个字节数量的可变长度列(variable-length columns)开始,后跟可变长度列偏移数组(variable-length column offset array)。 即使值为空,SQL Server 也会为每行中的每个可变长度列存储两个字节的偏移值。它后跟数据的实际可变长度部分。(它 指 可变长度列偏移数组)
最后,在行的末尾有可选的14字节版本控制标记。 该标记在操作期间使用,这需要行版本控制,例如联机索引重建,乐观隔离级别等。
行结构补充
至于 Status Bits A 的 8位 有更具体的定义:
位 | 含义 |
---|---|
Bit 0 | Versioning information. In SQL server 2008 this is always 0 |
Bits 1 to 3 | This is three bit value define the record type. |
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 | |
Bit 4 | Null bitmap exists or not.In SQL server 2008 null bitmap exists even if there is no null able columns |
Bit 5 | Indicate variable column exists or not. |
Bit 6 | Indicate that row contain versioning information |
Bit 7 | Not used in SQL server |
对于 Status Bits B :
Only one bit is used in this to indicate that the record is ghost forwarded record.
实例
例一 详
此例来自 http://aboutsqlserver.com/2013/10/15/sql-server-storage-engine-data-pages-and-data-rows/
首先,让我们创建表,用一些数据填充它并查看实际的行数据。
use tempdb
go
create table dbo.DataRows
(
ID int not null,
Col1 varchar(255) null,
Col2 varchar(255) null,
Col3 varchar(255) null
);
insert into dbo.DataRows(ID, Col1, Col3) values (1,replicate('a',255),replicate('c',255));
insert into dbo.DataRows(ID, Col2) values (2,replicate('b',255));
dbcc ind
(
'tempdb' -- Database name
,'dbo.DataRows' -- Table Name
,-1 -- Display info about all pages from the table
);
没有文档但很出名的 DBCC IND
命令返回有关表页分配的信息。
有两个属于该表的页面。第一个 PageType = 10 是名为 IAM 分配映射页面的特殊类型。此页面跟踪属于特定对象的页面。我们现在不关注它 - 我们将在以后博客文章中介绍分配映射页面(allocation map pages)。(这个要去看原作者的博文了)
PageType = 1 的页面是包含数据行的实际数据页面。 PageFID 和 PagePID 列显示页面的实际文件和页码。 你可以使用另一个没有文档的命令 DBCC PAGE
来检查其内容
-- Redirecting DBCC PAGE output to console rather than error log
dbcc traceon(3604);
dbcc page
(
'tempdb' -- Database name
,1 -- File ID
,214643 -- Page ID
,3 -- Output mode: 3 - display page header and row details
);
你可以看到 DBCC PAGE 的输出,该输出对应于下面的第一个数据行。 SQL Server 以字节交换顺序存储数据。 例如,两字节值 0001 将存储为 0100。(叨叨一嘴,是大小端模式?)
Slot 0 Offset 0x60 Length 39
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP VARIABLE_COLUMNS
Record Size = 39
Memory Dump @0x000000000EABA060
0000000000000000:30000800 01000000 04000403 001d001d 00270061 0................'.a
0000000000000014:61616161 61616161 61636363 63636363 636363 aaaaaaaaacccccccccc
Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4
ID = 1
Slot 0 Column 2 Offset 0x13 Length 10 Length (physical) 10
Col1 = aaaaaaaaaa
Slot 0 Column 3 Offset 0x0 Length 0 Length (physical) 0
Col2 = [NULL]
Slot 0 Column 4 Offset 0x1d Length 10 Length (physical) 10
Col3 = cccccccccc
我们来看看数据行结构:
如你所见,该行以两个状态位字节开始,后跟两个字节的值 0800。这是字节 0008 的交换值,它是行中列数属性的偏移量。 此偏移量告诉 SQL Server 行的固定长度数据部分(fixed-length data part)在哪里结束。
接下来的四个字节用于存储固定长度的数据,在我们的例子中是 ID 列。 之后,有两个字节的值表明数据行有四列,后跟一个字节的 NULL 位图。 位图中只有四列一个字节就足够了。 它以二进制格式存储 04 的值 00000100。 它表示该行中的第三列包含 NULL 值。
接下来的两个字节存储行中可变长度列的数量,即 3(按字节交换顺序为 0300)。 它由偏移数组跟随,其每两个字节存储可变长度列数据结束地方的偏移量。 如你所见,即使 Col2 为 NULL,它仍然使用 offset-array 中的槽(slot)。 最后,是来自可变长度列的实际数据。
ps. 还有个命令 dbcc traceon(3604)
大家可以了解下。
例二 略
参考资料
http://aboutsqlserver.com/2013/10/15/sql-server-storage-engine-data-pages-and-data-rows/
http://www.sqlservercentral.com/blogs/practicalsqldba/2012/08/22/sql-serverunderstanding-the-data-record-structure/
这两篇可以再去看看,我没摘全。
发完博客在相关文章里看到有一篇也是介绍 数据行结构
的:
https://blog.****.net/yangmeng518889/article/details/53911358