存储引擎内幕:启动页校验和会丢弃页残损保护吗?
原文地址:http://www.sqlskills.com/BLOGS/PAUL/post/Inside-The-Storage-Engine-Does-turning-on-page-checksums-discard-any-torn-page-protection.aspx
(译者:本文想说的是当修改了数据库的页保护方式(由残损保护改为校验和保护),以前已存在的页的保护方式是不会失效的,而且直到下次写磁盘时才会改为新的保护方式的。这是因为:数据库的页保护方式记录在启动页(boot page, 第9 页)的dbi_status 字段中,而页当前的保护方式记录在页头的m_flagBits 字段中。)
译文:
在我现在教的微软认证架构师课堂上,有人提出了一个很有意思的问题:如果数据库原来是页残损保护,现在改成校验和保护了,那么是否所有已存在的页残损保护都会丢失呢?
这是一个很重要的问题,因为将数据库改成页校验和 保护并不是立即将所有已分配页改为校验和 保护(你要将页读取至缓存池中、修改它并将其写回到磁盘中,只有在这时页才会是校验和保护)。所以如果因为启动数据库页校验和保护而使所有已存在的页的残损保护都失效的话,那么在页改为校验和保护之前,这些页是不会得到任何保护的。是这样的吗?我不记得答案了,下面我做了个实验。
我的想法是:先创建一个页残损保护的数据库,然后创建一个用来模拟页残损保护的表,接着置数据库为页校验和保护,此时看看残损页是否还会报错。
-- 建立一个测试数据库
USE master ;
GO
CREATE DATABASE ChecksumTest ;
GO
USE ChecksumTest ;
GO
-- 将数据库置为页残损保护
ALTER DATABASE ChecksumTest SET PAGE_VERIFY TORN_PAGE_DETECTION ;
GO
-- 创建一个测试表,插入一行。
CREATE TABLE BrokenTable ( c1 INT , c2 CHAR ( 1000));
INSERT INTO BrokenTable VALUES ( 1, 'a' );
GO
-- 确保页写入磁盘,并从缓存池中删除。
CHECKPOINT ;
GO
DBCC DROPCLEANBUFFERS ;
GO
现在我们来检查一下页。在页头部有两个比特位用来说明页是残损保护还是校验和保护。具体地说就是:如果残损保护,那么字段 m_flagBits 会置上 0x100 ;如果是校验和保护,那么 m_flagBits 会置上 0x200 ,而且页并没有被修改(也就是说,校验和仍然有效)。因为当页被读取至缓存池中时,系统会去除 m_flagBits 字段上的残损保护编码的,所以你应当不会看到 0x100 被置上——当然前提是页不是真的残损,如果真是页残损的话, 0x100 肯定会被置上的。
sp_allocationmetadata 'BrokenTable' ;
GO
DBCC TRACEON ( 3604 );
GO
DBCC PAGE ( 'ChecksumTest' , 1 , 143 , 3 );
GO
<snip>
m_pageId = (1:143) m_headerVersion = 1 m_type = 1
m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x8000
m_objId (AllocUnitId.idObj) = 67 m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594042318848
Metadata: PartitionId = 72057594038321152 Metadata: IndexId = 0
Metadata: ObjectId = 2073058421 m_prevPage = (0:0) m_nextPage = (0:0)
pminlen = 1008 m_slotCnt = 2 m_freeCnt = 6070
m_freeData = 2118 m_reservedCnt = 0 m_lsn = (28:183:2)
m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0
m_tornBits = 770
<snip>
这时,页残损保护的编码( 0x100 )已经去除,而且数据页是好的。一旦将磁盘中的页破坏了,这时还可以用 DBCC PAGE 查看页。下面是我将页破坏了,由 DBCC PAGE 输出的内容(译注:正如上面所说,当页被破坏了, m_flagBits 中 0x100 肯定会被置上):
m_pageId = (1:143) m_headerVersion = 1 m_type = 1
m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x8100
m_objId (AllocUnitId.idObj) = 67 m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594042318848
Metadata: PartitionId = 72057594038321152 Metadata: IndexId = 0
Metadata: ObjectId = 2073058421 m_prevPage = (0:0) m_nextPage = (0:0)
pminlen = 1008 m_slotCnt = 1 m_freeCnt = 7083
m_freeData = 1107 m_reservedCnt = 0 m_lsn = (28:81:20)
m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0
m_tornBits = 41949233
此时如果我再查询表,我会得到:
SELECT * FROM BrokenTable ;
GO
Msg 824, Level 24, State 2, Line 1
SQL Server detected a logical consistency-based I/O error: torn page (expected signature: 0xaaaaaaaa; actual signature: 0xaaaaa82a). It occurred during a read of page (1:143) in database ID 8 at offset 0x0000000011e000 in file 'C:/Program Files/Microsoft SQL Server/MSSQL.1/MSSQL/DATA/ChecksumTest.mdf'. Additional messages in the SQL Server error log or system event log may provide more detail. This is a severe error condition that threatens database integrity and must be corrected immediately. Complete a full database consistency check (DBCC CHECKDB). This error can be caused by many factors; for more information, see SQL Server Books Online.
现在问题的关键是:如果此时将数据库改为校验和保护,是否还报告页残损错误 。我们来试试:
ALTER DATABASE checksumtest SET PAGE_VERIFY CHECKSUM ;
GO
SELECT * FROM BrokenTable ;
GO
Msg 824, Level 24, State 2, Line 1
SQL Server detected a logical consistency-based I/O error: torn page (expected signature: 0xaaaaaaaa; actual signature: 0xaaaaa82a). It occurred during a read of page (1:143) in database ID 8 at offset 0x0000000011e000 in file 'C:/Program Files/Microsoft SQL Server/MSSQL.1/MSSQL/DATA/ChecksumTest.mdf'. Additional messages in the SQL Server error log or system event log may provide more detail. This is a severe error condition that threatens database integrity and must be corrected immediately. Complete a full database consistency check (DBCC CHECKDB). This error can be caused by many factors; for more information, see SQL Server Books Online.
酷!所以最终的答案是 YES ——残损页保护仍然有效。因为页头部的有两个比特位保存着页正在使用的保护算法。实际上,你就是关闭了数据库的校验和保护和残损保护(译注:将它置为 NONE 保护),数据页原来的保护还是有效的。