Sql-Server

備份壓縮導致 SQL 2017 TDE 數據庫損壞

  • January 11, 2018

在 SQL Server 2017 (CU3) 上,每當我在我的一個 TDE 數據庫上啟用備份壓縮時,備份過程總是會損壞數據庫中的特定頁面。如果我在沒有壓縮的情況下執行備份,它不會被損壞。以下是我為驗證和重現此問題所採取的步驟:

  1. 在數據庫“TDE_DB1”上執行 DBCC CheckDB;一切都很好,沒有錯誤;
  2. 無壓縮成功備份數據庫;RESTORE VERIFYONLY 說一切都很好;
  3. 成功恢復數據庫為“TDE_DB2”;一切都很好,DBCC CheckDB 沒有顯示錯誤;
  4. 成功備份“TDE_DB1”數據庫 WITH 壓縮;RESTORE VERIFYONLY 錯誤,說“檢測到備份集損壞”;
  5. 嘗試將數據庫恢復為“TDE_DB2”;錯誤,說“RESTORE 在數據庫中的頁面 (1:92454) 上檢測到錯誤”
  6. 重複步驟1-3;一切都很好;
  7. 刪除“TDE_DB1”和“TDE_DB2”;從備份中恢復“TDE_DB1”;一切都很好;
  8. 重複步驟1-5;得到相同的結果;

總結一下:數據庫和定期備份似乎很好,在數據庫上執行 CHECKDB 並在備份上執行 VERIFYONLY 不會報告任何錯誤。使用壓縮備份數據庫似乎會導致損壞。

以下是有錯誤的程式碼範例。(注意:對 TDE 數據庫使用壓縮需要 MAXTRANSFERSIZE

-- Good, completes with no corruption;
BACKUP DATABASE [TDE_DB1] TO DISK = N'E:\MSSQL\Backup\TDE_DB1a.bak' WITH CHECKSUM;
RESTORE VERIFYONLY FROM DISK = N'E:\MSSQL\Backup\TDE_DB1a.bak' WITH CHECKSUM;

RESTORE DATABASE [TDE_DB2]
FROM DISK = 'E:\MSSQL\Backup\TDE_DB1a.bak'
WITH MOVE 'DataFileName' to 'E:\MSSQL\Data\TDE_DB2.mdf'
,MOVE 'LogFileName' to 'F:\MSSQL\Log\TDE_DB2_log.ldf';


-- Bad, I haz corruption;
BACKUP DATABASE [TDE_DB1] TO DISK = N'E:\MSSQL\Backup\TDE_DB1b.bak' WITH CHECKSUM, COMPRESSION, MAXTRANSFERSIZE = 131072;
RESTORE VERIFYONLY FROM DISK = N'E:\MSSQL\Backup\TDE_DB1b.bak' WITH CHECKSUM;
-- ERROR
--Msg 3189, Level 16, State 1, Line 1
--Damage to the backup set was detected.
--Msg 3013, Level 16, State 1, Line 1
--VERIFY DATABASE is terminating abnormally.

RESTORE DATABASE [TDE_DB2]
FROM DISK = 'E:\MSSQL\Backup\TDE_DB1b.bak'
WITH MOVE 'DataFileName' to 'E:\MSSQL\Data\TDE_DB2.mdf'
,MOVE 'LogFileName' to 'F:\MSSQL\Log\TDE_DB2_log.ldf';
-- ERROR
--Msg 3183, Level 16, State 1, Line 7
--RESTORE detected an error on page (1:92454) in database "TDE_DB2" as read from the backup set.
--Msg 3013, Level 16, State 1, Line 7
--RESTORE DATABASE is terminating abnormally.

然後我嘗試檢查報告為有錯誤的頁面(它始終是同一頁面。),但 DBCC PAGE 報告 ObjectId 為 0。 根據 Paul Randal 的這篇文章,這意味著沒有找到元數據,並且原因之一可能是頁面本身已損壞,並且用於嘗試查找元數據的值不正確。他的建議是執行 CHECKDB,但我不能這樣做,因為損壞的備份無法恢復。

我嘗試了此 SO Post中的建議(將 INIT 和 FORMAT 添加到 BACKUP 命令)來重置元數據,但這似乎沒有改變任何東西,我仍然在壓縮備份中遇到損壞。

這只發生在我的一個 TDE 數據庫中。我在同一台伺服器上還有 4 個其他 TDE 數據庫,它們沒有這個問題。這告訴我這個特定數據庫可能存在潛在問題。我意識到簡單的解決方案就是不使用壓縮,但我覺得這實際上可能是對未來更大問題的預警。

有沒有人以前見過這個,或者知道為什麼壓縮會損壞該頁面?在這一點上,我有點不知道下一步該做什麼。我考慮從較早的備份中恢復頁面,但我認為這並不重要,因為正常數據庫中的頁面看起來不錯。

更新 1: 以下是 DBCC PAGE 的結果,選項為 0:

DBCC 執行完成。如果 DBCC 列印錯誤消息,請聯繫您的系統管理員。

頁:(1:92454)

緩衝:

BUF @0x000002187AE55640

BPAGE = 0x0000021848650000 Bhash = 0x000000000000000000

BPageno =(1:92454)BDBID = 8 Breferences = 0 Bcputicks = 563 Bsamplecount = 1

Buse1 = 51429 BStat = 0x809部落格= 0​​x15a Bnext = 0x15a

Bnext = 0x000000000000000000 BSTAT = 0x00000000

頁眉:

頁面@0x000002184865E000

m_pageid =(1:92454)m_headerversion = 111

m_type = 189 m_typeflagbits = 0x2d m_level = 197

m_flagbits = 0x525e m_objid(allocunitid.idobj)= 788815194

m_indexid(allocunitid.idind)= 515元數據:Allocunitid = 145011308798541824元數據:partitionData = 0元數據: IndexID = -1元數據:ObjectID = 0 m_prevpage =(32842:1881351155)m_nextpage =(13086:-560562340)

pminlen = 36067 m_slotcnt = 8149 m_freecnt = 5149 m_freeData = 7295 m_reservedcnt = 4810 m_lsn =(742012401:720884976:30191)m_xactreserved = 14755

m_xdesId = (12811:1559482793) m_ghostRecCnt = 12339

m_tornBits = -1381699202 DB Frag ID = 1

分配狀態

GAM (1:2) = 已分配 SGAM (1:3) =

未分配 PFS (1:88968) = 0x0 0_PCT_FULL DIFF (1:6) = 未更改

ML (1:7) = 未記錄

如果我嘗試使用其他選項執行 DBCC PAGE,則會收到以下錯誤:

DBCC PAGE with option 1: Msg 0, Level 11, State 0, Line 0 目前命令出現嚴重錯誤。結果,如果有的話,應該丟棄。

帶有選項 3 的 DBCC PAGE:消息 2514,級別 16,狀態 5,第 3 行發生 DBCC PAGE 錯誤:無效的頁麵類型 - 無法轉儲樣式 3。

更新 2: 以下是 sys.dm_db_database_page_allocations DMO 的一些結果:

的object_id = 75 index_id的= 1 rowset_id = 281474981625856 allocation_unit_id = 281474981625856

allocation_unit_type = 1 allocation_unit_type_desc = IN_ROW_DATA extent_file_id = 1 extent_page_id = 92448

allocated_page_iam_file_id = 1 allocated_page_iam_page_id = 104

allocated_page_file_id = 1 allocated_page_page_id = 92454

is_allocated = 0 is_iam_page = 0 is_mixed_page_allocation = 0

看起來這個問題與在其上執行了 SHRINK 操作的數據庫有關。就我而言,我在 SQL Server 2014 上複製了一個生產數據庫(已使用 TDE 加密),在數據和日誌文件上執行 DBCC SHRINKFILE,然後在我的新 SQL 上進行備份和恢復2017 伺服器。(縮小的原因是為了減小大小以更快地傳輸備份。)

作為測試,我恢復了一個未在其上執行 DBCC SHRINKFILE 的數據庫副本,並且它在壓縮備份時沒有出現損壞問題。

所以,總結一下,我的測試結果如下:

  • 此“縮小”TDE 數據庫上的正常備份/恢復操作在 SQL 2017 中正常工作
  • 壓縮“縮小”的 TDE 數據庫的備份似乎會導致 sys.sysmultiobjrefs 表損壞
  • 壓縮正常 TDE 數據庫的備份(沒有執行 DBCC SHRINKFILE)正常工作並且不報告損壞

我不知道這是否是 SQL Server 2017 中已確認的錯誤,但我已將我的發現發送給 Microsoft 以供他們查看。

所以,這個故事的寓意是:不要收縮你的數據庫!曾經!:)

引用自:https://dba.stackexchange.com/questions/195078