第4/24周 页面限制8060 bytes

时间:2021-06-19 17:34:59

恭喜您!在你面前就只剩下几页了,然后你就可以完成第1个月的SQL Server性能调优培训了。今天我将讲下页的一些限制,还有为什么你会喜欢这些限制,同时也会讨厌这些限制。

正如你在第2周学到的,数据页始终是8kb 的大小,而且你只能在上面存储8060 bytes。你的记录大小指示你在一个页里可以存储多少记录。当你与像CHAR,INT,DATETIME等定长类型数据类型打交道时,你会发现SQL Server有记录长度不能超过8060 bytes长度(包含7 bytes 的内部行开销)的限制。

页面限制——好的一面

当你的表少于8列时,你需要(为每条记录)增加额外7 bytes 的内部行开销。对每增加的8列都要增加额外的1 byte, 例如,17列,你需要9 btyes的内部行开销(7+1+1)。如果你尝试创建更长的记录大小,SQL Server会在你执行CREATE TABLE语句时返回一个错误信息给你。来看看下面的表定义:

 CREATE TABLE TooLargeTable1
(
   Column1 CHAR(5000),
   Column2 CHAR(3000),
   Column3 CHAR(54)
)
GO

正如你所见,每条记录需要8061 bytes(5000+3000+54+7 bytes)。因此在这种情况下,当你尝试去创建这个表时,SQL Server会返回下列的错误信息。

第4/24周 页面限制8060 bytes

当你创建超过8列的表时,你需要把SQL Server需要的8 bytes的行内部开销也算进去。

 CREATE TABLE TooLargeTable2
(
   Column1 CHAR(1000) NOT NULL,   Column2 CHAR(1000) NOT NULL,
   Column3 CHAR(1000) NOT NULL,   Column4 CHAR(1000) NOT NULL,
   Column5 CHAR(1000) NOT NULL,   Column6 CHAR(1000) NOT NULL,
   Column7 CHAR(1000) NOT NULL,   Column8 CHAR(1000) NOT NULL,
   Column9 CHAR(53) NOT NULL
)
GO

因此这里又是一个非法的表定义(8000+53+8 bytes),这里SQL Server会返回一个错误信息。

第4/24周 页面限制8060 bytes

页面限制——坏的一面

在上一环节我已经向你展示了页面限制你喜欢的一面,因为当你在创建这样表的时候,SQL Server会返回你一个错误信息。但是页面限制也有你讨厌的一面,因为SQL Server会允许你创建这样的表,而且有时INSERT语句执行成功,有时却会失败……我们来看下。

这里我们面对的问题是与像VARCHAR等变长数据类型。当这些列不能存在它本身页时,SQL Server会把它们移动到在另外页面的行偏移位置。这个被称为 行溢出页(Row-Overflow page)。SQL Server会在原来的页面留下24 bytes长的指向行溢出页的指针。

在于其他列组合时的某些情况下,这个指针会溢出8060 bytes的限制。我们来看下下面的表定义:

 CREATE TABLE TooLargeTable3
(
   Column1 CHAR(5000),
   Column2 CHAR(3000),
   Column3 CHAR(30),
   Column4 VARCHAR(3000)
)
GO

如你所见,这里我使用了VARCHAR(3000)的数据类型。你会看到SQL Server这里会给你一个警告信息。这个警告提示你可以创建这个表,但在执行INSERT/UPDATE语句时可能会失败……

第4/24周 页面限制8060 bytes

下面在表里的插入语句会成功:

 INSERT INTO TooLargeTable3 VALUES
(
   REPLICATE('x', 5000),
   REPLICATE('x', 3000),
   REPLICATE('x', 30),
   REPLICATE('x', 19)
)
GO

这里的记录大小是8056 bytes长(5000+3000+30+19+7 bytes)。在这个情况下,SQL Server会把第4列的数据保存在主数据页。但是想像下下面的INSERT语句:

 INSERT INTO TooLargeTable3 VALUES
(
   REPLICATE('x', 5000),
   REPLICATE('x', 3000),
   REPLICATE('x', 30),
   REPLICATE('x', 3000)
)
GO 

在刚才的INSERT语句,SQL Server会把第4列数据移到行溢出页(row-overflow page),因为这3000 bytes 不能在主数据页里放下。这也就意味着SQL Server会在这里留下一个指向不同页且24bytes 长的指针,在那个位置可以找到数据。但是我们的记录大小现在是8061 bytes长(5000+3000+30+24+7 bytes)。

Duang,你的记录长度超过8060 bytes,INSERT语句执行失败了!

第4/24周 页面限制8060 bytes

这些就是坏的限制,因为他们在数据库操作的时候隐藏着,好的一面就是在你定义表架构的时候如上所示可见的。想想看是啥?

小结

在你设计你的表结构时,你要非常仔细的想下你的操作。在SQL Server里与页打交道时你会碰到很多这样的执行进去后才出现的限制。当然,在SQL Server给你错误信息时,你不允许创建这个表,基本上就天下太平了。

当当你收到警告时,基本上每个人会想不都不想下就忽略掉。这始终是个坏的操作,因为你已经看到了,你的INSERT可能在运行时失败,问题的发生你是可以预见的。我希望你现在已经明白这个性能调优培训是个很好内幕公开,并且为什么理解数据页的内部结构是多么重要!

在接下来的培训我会讲解SQL Server中堆表的更多细节,还有为什么它们有时是好的(设计),有时候却是不好的(设计) 。请继续关注,并且好好享受剩下的7天!

围观PPT:

0511_04页面限制8060_bytes.rar