Quantcast
Channel: FradenSQL » Uncategorized
Viewing all articles
Browse latest Browse all 5

Writing Checksums by Reindexing

$
0
0

I recently came across a couple databases that didn’t have any recovery model set.  Gotta love vendors.  Anyway, I know that turning on the checksum recovery model doesn’t put a checksum on each page.  Rather, it’s written the next time the page is written to disk.  This can lead to a gap where some pages never get a checksum written to them.  Since there’s no “DBCC CREATE_CHECKSUM” command we need to look for another way to do it to write the checksum for tables that aren’t modified often.

Verifying Checksum

Before we do anything else we need to know how to verify whether or not there’s a checksum on the page.  To do that I used the method Colleen Morrow used when she discussed switching from torn page to checksum recovery models.  As she shows, the checksum is stored in the m_tornBits field of the page header instead of a separate field.  We’ll be using that to confirm when the checksum is written.

Setup

We’re going to create a database, modify the recovery model and create a clustered table.  Finally, we’re going to insert some data and do a checkpoint to make sure all the data is written to disk.

CREATE DATABASE ChecksumTest;
GO
 
ALTER DATABASE ChecksumTest
SET PAGE_VERIFY NONE;
GO
 
USE ChecksumTest
 
CREATE TABLE dbo. clusteredTable (
id INT IDENTITY ( 1,1 ) NOT NULL,
name VARCHAR (255) NOT NULL,
CONSTRAINT PK_ClusteredTable PRIMARY KEY (id )
);
 
INSERT INTO dbo. clusteredTable
SELECT TOP 1000 b. name FROM sys. objects a
CROSS APPLY sys. objects b ;
GO
CHECKPOINT
GO

Now that we have the data there we should confirm that there isn’t a checksum on the page already.  First we’ll set trace flag 3604 so we can see the output of one of the commands in the query window then we’ll use DBCC IND to see what pages are on the table.  Lastly, we’ll use DBCC PAGE to look at the page itself.

DBCC TRACEON (3604 );
GO
 
DBCC IND ('ChecksumTest' ,'clusteredTable', 1);
GO
/* DBCC IND Results:
PageFID PagePID     IAMFID IAMPID      ObjectID    IndexID     PartitionNumber PartitionID          iam_chain_type       PageType IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID
------- ----------- ------ ----------- ----------- ----------- --------------- -------------------- -------------------- -------- ---------- ----------- ----------- ----------- -----------
1       154         NULL   NULL        2105058535  1           1               72057594038779904    In-row data          10       NULL       0           0           0           0
1       153         1      154         2105058535  1           1               72057594038779904    In-row data          1        0          1           156         0           0
1       155         1      154         2105058535  1           1               72057594038779904    In-row data          2        1          0           0           0           0
1       156         1      154         2105058535  1           1               72057594038779904    In-row data          1        0          1           157         1           153
1       157         1      154         2105058535  1           1               72057594038779904    In-row data          1        0          1           158         1           156
1       158         1      154         2105058535  1           1               72057594038779904    In-row data          1        0          0           0           1           157
 
(6 row(s) affected)
*/
 
--Picking a random page type 1 row from above
DBCC PAGE (ChecksumTest, 1,156 ,1)
GO

And here is the relevent part of the results from the DBCC PAGE call:

PAGE: (1:156)
<snip>

PAGE HEADER:

Page @0x0000000085C2C000

m_pageId = (1:156)                   m_headerVersion = 1                  m_type = 1
m_typeFlagBits = 0x4                 m_level = 0                          m_flagBits = 0x0
m_objId (AllocUnitId.idObj) = 27     m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594039697408
Metadata: PartitionId = 72057594038779904                                 Metadata: IndexId = 1
Metadata: ObjectId = 2105058535      m_prevPage = (1:153)                 m_nextPage = (1:157)
pminlen = 8                          m_slotCnt = 313                      m_freeCnt = 13
m_freeData = 7553                    m_reservedCnt = 0                    m_lsn = (21:184:538)
m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
m_tornBits = 0

Notice that the m_tornBits value is 0 meaning there’s no page recovery written to this page.

Write that Checksum

Qe’re going to enable the checksum recovery model and see what we can to to get a checksum written to the page.  First we’re going to try an index reorg.  We’re also going to do a checkpoint after the reorg just to make absolutely sure that there’s nothing just floating around in memory.

ALTER DATABASE ChecksumTest SET PAGE_VERIFY CHECKSUM
GO
 
ALTER INDEX PK_ClusteredTable ON clusteredTable REORGANIZE
GO
CHECKPOINT
GO
 
DBCC IND ('ChecksumTest' ,'clusteredTable', 1);
GO
--The output is the same as above so we check the same page.
 
DBCC PAGE (ChecksumTest, 1,156 ,1)
GO

And that same section of DBCC PAGE from above:

PAGE: (1:156)

PAGE HEADER:

Page @0x0000000085C2C000

m_pageId = (1:156)                   m_headerVersion = 1                  m_type = 1
m_typeFlagBits = 0x4                 m_level = 0                          m_flagBits = 0x0
m_objId (AllocUnitId.idObj) = 27     m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594039697408
Metadata: PartitionId = 72057594038779904                                 Metadata: IndexId = 1
Metadata: ObjectId = 2105058535      m_prevPage = (1:153)                 m_nextPage = (1:157)
pminlen = 8                          m_slotCnt = 313                      m_freeCnt = 13
m_freeData = 7553                    m_reservedCnt = 0                    m_lsn = (21:184:538)
m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
m_tornBits = 0

m_tornBits is still 0 so that didn’t do it.  There may be cases where it does, such as if the pages are actually out of order, but this does confirm it won’t always happen.  Let’s see what happens when we do a rebuild instead of a reorg.  Again, we’re doing a reindex just to make sure everything gets to disk and verify the page numbers with DBCC IND.

ALTER INDEX PK_ClusteredTable ON clusteredTable REBUILD
GO
CHECKPOINT
GO
 
DBCC IND ('ChecksumTest' ,'clusteredTable', 1);
GO

If we look at the output of DBCC IND this time we see a different output:

PageFID PagePID     IAMFID IAMPID      ObjectID    IndexID     PartitionNumber PartitionID          iam_chain_type       PageType IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID
------- ----------- ------ ----------- ----------- ----------- --------------- -------------------- -------------------- -------- ---------- ----------- ----------- ----------- -----------
1       168         NULL   NULL        2105058535  1           1               72057594038845440    In-row data          10       NULL       0           0           0           0
1       159         1      168         2105058535  1           1               72057594038845440    In-row data          1        0          1           169         0           0
1       169         1      168         2105058535  1           1               72057594038845440    In-row data          1        0          1           171         1           159
1       170         1      168         2105058535  1           1               72057594038845440    In-row data          2        1          0           0           0           0
1       171         1      168         2105058535  1           1               72057594038845440    In-row data          1        0          1           172         1           169
1       172         1      168         2105058535  1           1               72057594038845440    In-row data          1        0          0           0           1           171

All the page numbers are different.  This is an indication we’re probably going to see a checksum.  Again, picking a random page with a page type of 1:

DBCC PAGE (ChecksumTest, 1,171 ,1)
GO

We now see that m_tornBits has a value indicating that the checksum has been written.

PAGE: (1:171)
<snip>

PAGE HEADER:

Page @0x0000000085AA0000

m_pageId = (1:171)                   m_headerVersion = 1                  m_type = 1
m_typeFlagBits = 0x0                 m_level = 0                          m_flagBits = 0x200
m_objId (AllocUnitId.idObj) = 28     m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594039762944
Metadata: PartitionId = 72057594038845440                                 Metadata: IndexId = 1
Metadata: ObjectId = 2105058535      m_prevPage = (1:169)                 m_nextPage = (1:172)
pminlen = 8                          m_slotCnt = 303                      m_freeCnt = 23
m_freeData = 7563                    m_reservedCnt = 0                    m_lsn = (22:16:48)
m_xactReserved = 0                   m_xdesId = (0:0)                     m_ghostRecCnt = 0
m_tornBits = 1602034681

Conclusion

This still isn’t a low-intensity way to get checksums written for each page.  It is something that can be done an index at a time that could have a side benefit as well.  Care should be taken when using this, such as doing it online where available or doing it offline, but it’s a useful tool to make sure that after switching to full recovery model that the checksum gets written to little modified pages.

The post Writing Checksums by Reindexing appeared first on FradenSQL.


Viewing all articles
Browse latest Browse all 5

Latest Images

Trending Articles



Latest Images