在 SQL Server 中,为什么在行中存储 9B 的 tinyint。由于某种原因,NULL 位图掩码的末尾似乎多了一个字节。
使用临时数据库; 去 创建表表 ( 我 TINYINT 不为空 ); 去 插入表 (i) 价值观 (1) ; 去 DBCC IND ('tempdb','tbl',-1) ; 去 DBCC TRACEON (3604) ; -- 页面转储将转到控制台 去 DBCC PAGE ('tempdb',1,168,3) ; 去
结果(由于 DBCC PAGE 首先显示最低有效字节,我反转了字节):
Record Size = 9B
10000500 01010000 00
TagA = 0x10 = 1B
TagB = 0x00 = 1B
Null Bitmap Offset = 0x0005 = 2B
Our integer column = 0x01 = 1B
Column Count = 0x0001 = 2B
NULL Bitmap = 0x0000 = 2B (what!?)
如果您使用简单的大小加法计算记录,您确实会得到 8:4+1+2+1(标头+固定大小+空位图计数+空位图本身)。但是堆记录不能小于转发存根大小,即 9 个字节,因为记录必须保证它可以被转发存根替换。因此,记录实际上将增加 9 个字节。通过计算和最小大小, A
smallint
都是 9 字节。任何更大的东西都已经比转发存根大,所以你的计算大小与记录大小相匹配。很高兴听到作者的声音。:-) Kalen 怀疑这只是某种最小行长度的强制执行,其中小于 9 的任何内容都被填充到 9。当然,只有少数情况下这是可能的。您会发现 TINYINT 和 BIT 以及 VARCHAR(1)/CHAR(1) 的幻影字节。如果您移动到 SMALLINT 或 CHAR(2),它不会增加超过 9,但如果您移动到 CHAR(3),它会增加。
因此,从本质上讲,您可以指出通过明智地选择数据类型可以获得的效率,但要指出在某些边缘情况下,由于存储层的其他因素,规则不成立。
编辑我希望能为您提供更具体的信息。只是想让您知道,这就是 Internals 一书的作者目前的想法。她不是百分百确定。