恭喜您!在你面前就只剩下几页了,然后你就可以完成第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语句时返回一个错误信息给你。来看看下面的表定义:
1 CREATE TABLE TooLargeTable1 2 ( 3 Column1 CHAR(5000), 4 Column2 CHAR(3000), 5 Column3 CHAR(54) 6 ) 7 GO
正如你所见,每条记录需要8061 bytes(5000+3000+54+7 bytes)。因此在这种情况下,当你尝试去创建这个表时,SQL Server会返回下列的错误信息。
当你创建超过8列的表时,你需要把SQL Server需要的8 bytes的行内部开销也算进去。
1 CREATE TABLE TooLargeTable2 2 ( 3 Column1 CHAR(1000) NOT NULL, Column2 CHAR(1000) NOT NULL, 4 Column3 CHAR(1000) NOT NULL, Column4 CHAR(1000) NOT NULL, 5 Column5 CHAR(1000) NOT NULL, Column6 CHAR(1000) NOT NULL, 6 Column7 CHAR(1000) NOT NULL, Column8 CHAR(1000) NOT NULL, 7 Column9 CHAR(53) NOT NULL 8 ) 9 GO
因此这里又是一个非法的表定义(8000+53+8 bytes),这里SQL Server会返回一个错误信息。
页面限制——坏的一面
在上一环节我已经向你展示了页面限制你喜欢的一面,因为当你在创建这样表的时候,SQL Server会返回你一个错误信息。但是页面限制也有你讨厌的一面,因为SQL Server会允许你创建这样的表,而且有时INSERT语句执行成功,有时却会失败……我们来看下。
这里我们面对的问题是与像VARCHAR等变长数据类型。当这些列不能存在它本身页时,SQL Server会把它们移动到在另外页面的行偏移位置。这个被称为 行溢出页(Row-Overflow page)。SQL Server会在原来的页面留下24 bytes长的指向行溢出页的指针。
在于其他列组合时的某些情况下,这个指针会溢出8060 bytes的限制。我们来看下下面的表定义:
1 CREATE TABLE TooLargeTable3 2 ( 3 Column1 CHAR(5000), 4 Column2 CHAR(3000), 5 Column3 CHAR(30), 6 Column4 VARCHAR(3000) 7 ) 8 GO
如你所见,这里我使用了VARCHAR(3000)的数据类型。你会看到SQL Server这里会给你一个警告信息。这个警告提示你可以创建这个表,但在执行INSERT/UPDATE语句时可能会失败……
下面在表里的插入语句会成功:
1 INSERT INTO TooLargeTable3 VALUES 2 ( 3 REPLICATE('x', 5000), 4 REPLICATE('x', 3000), 5 REPLICATE('x', 30), 6 REPLICATE('x', 19) 7 ) 8 GO
这里的记录大小是8056 bytes长(5000+3000+30+19+7 bytes)。在这个情况下,SQL Server会把第4列的数据保存在主数据页。但是想像下下面的INSERT语句:
1 INSERT INTO TooLargeTable3 VALUES 2 ( 3 REPLICATE('x', 5000), 4 REPLICATE('x', 3000), 5 REPLICATE('x', 30), 6 REPLICATE('x', 3000) 7 ) 8 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语句执行失败了!
这些就是坏的限制,因为他们在数据库操作的时候隐藏着,好的一面就是在你定义表架构的时候如上所示可见的。想想看是啥?
小结
在你设计你的表结构时,你要非常仔细的想下你的操作。在SQL Server里与页打交道时你会碰到很多这样的执行进去后才出现的限制。当然,在SQL Server给你错误信息时,你不允许创建这个表,基本上就天下太平了。
当当你收到警告时,基本上每个人会想不都不想下就忽略掉。这始终是个坏的操作,因为你已经看到了,你的INSERT可能在运行时失败,问题的发生你是可以预见的。我希望你现在已经明白这个性能调优培训是个很好内幕公开,并且为什么理解数据页的内部结构是多么重要!
在接下来的培训我会讲解SQL Server中堆表的更多细节,还有为什么它们有时是好的(设计),有时候却是不好的(设计) 。请继续关注,并且好好享受剩下的7天!