Kompresi Cadangan Menyebabkan Korupsi Dalam SQL 2017 TDE Database

13

Pada SQL Server 2017 (CU3), setiap kali saya mengaktifkan kompresi cadangan pada salah satu basis data TDE saya, proses pencadangan selalu merusak halaman tertentu dalam basis data. Jika saya menjalankan cadangan tanpa kompresi, itu tidak rusak. Berikut langkah-langkah yang telah saya ambil untuk memverifikasi dan mereproduksi masalah ini:

  1. Jalankan DBCC CheckDB pada database "TDE_DB1"; semuanya baik, tidak ada kesalahan;
  2. Berhasil mencadangkan basis data tanpa kompresi; KEMBALIKAN VERIFYONLY berkata bahwa semuanya baik;
  3. Berhasil memulihkan basis data sebagai "TDE_DB2"; semua baik, DBCC CheckDB tidak menunjukkan kesalahan;
  4. Berhasil mencadangkan basis data "TDE_DB1" DENGAN kompresi; KEMBALI kesalahan VERIFYONLY, mengatakan "Kerusakan pada set cadangan terdeteksi";
  5. Mencoba mengembalikan database sebagai "TDE_DB2"; kesalahan, mengatakan "KEMBALIKAN terdeteksi kesalahan pada halaman (1: 92454) dalam database"
  6. Ulangi langkah 1-3; semua baik;
  7. DROP "TDE_DB1" dan "TDE_DB2"; Pulihkan "TDE_DB1" dari cadangan; semua baik;
  8. Ulangi langkah 1-5; dapatkan hasil yang sama;

Untuk meringkas: Basis data dan cadangan biasa tampak baik-baik saja, menjalankan CHECKDB pada database dan VERIFYONLY pada cadangan tidak melaporkan kesalahan. Mencadangkan database dengan kompresi tampaknya menyebabkan korupsi.

Di bawah ini adalah contoh kode dengan kesalahan. (Catatan: MAXTRANSFERSIZE diperlukan untuk menggunakan kompresi dengan basis data TDE )

-- 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.

Saya kemudian mencoba untuk memeriksa halaman yang dilaporkan memiliki kesalahan (Itu selalu halaman yang sama.), Tetapi DBCC PAGE melaporkan bahwa ObjectId adalah 0. Menurut artikel ini oleh Paul Randal itu berarti tidak ada metadata yang ditemukan, dan salah satu alasannya adalah halaman itu sendiri rusak dan nilai yang salah digunakan untuk mencoba mencari metadata. Sarannya adalah menjalankan CHECKDB, yang tidak dapat saya lakukan karena cadangan yang rusak tidak akan pulih.

Saya mencoba saran dari SO Post ini (Menambahkan INIT dan FORMAT ke perintah BACKUP) untuk mengatur ulang metadata, tetapi sepertinya tidak mengubah apa-apa, saya masih mendapatkan korupsi pada cadangan yang dikompres.

Ini hanya terjadi dengan salah satu basis data TDE saya. Saya memiliki 4 basis data TDE lain di server yang sama ini, dan mereka tidak memiliki masalah ini. Itu memberitahu saya bahwa mungkin ada masalah mendasar dengan database spesifik ini. Saya menyadari bahwa solusi yang mudah adalah dengan tidak menggunakan kompresi, tetapi saya merasa seperti ini sebenarnya bisa menjadi peringatan dini untuk masalah yang lebih besar yang muncul.

Adakah yang pernah melihat ini sebelumnya, atau tahu mengapa kompresi akan merusak halaman itu? Pada titik ini, saya agak bingung apa yang harus dilakukan selanjutnya. Saya mempertimbangkan memulihkan halaman dari cadangan sebelumnya, tetapi saya pikir itu tidak masalah karena halaman dalam database biasa tampak baik-baik saja.

UPDATE 1: Di bawah ini adalah hasil dari DBCC PAGE, dengan opsi 0:

Eksekusi DBCC selesai. Jika DBCC mencetak pesan kesalahan, hubungi administrator sistem Anda.

HALAMAN: (1: 92454)

PENYANGGA:

BUF @ 0x000002187AE55640

bpage = 0x000002184865E000 bhash = 0x000000000000000000
bpageno = (1: 92454) bdbid = 8 breagers = 0 bcputicks = 563 bsampleCount = 1
bUse1 = 51429 bstat = 0x809 blog = 0x15a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
b00

KEPALA HALAMAN:

Halaman @ 0x000002184865E000

m_pageId = (1: 92.454) m_headerVersion = 111
m_type = 189 m_typeFlagBits = 0x2d m_level = 197
m_flagBits = 0x525e m_objId (AllocUnitId.idObj) = 788.815.194
m_indexId (AllocUnitId.idInd) = 515 Metadata: AllocUnitId = 145011308798541824 Metadata: PartitionId = 0 Metadata: IndexId = -1 Metadata: ObjectId = 0 m_prevPage = (32842: 1881351155) m_nextPage = (13086: -560562340)
pminlen = 36067 m_slotCnt = 8149 m_freeCnt = 51871 m_freeData = 7295 mdcreable_countable_blacked_compter_edcantableata 14755
m_xdesId = (12811: 1559482793) m_ghostRecCnt = 12339
m_tornBits = -1381699202 DB Frag ID = 1

Status Alokasi

GAM (1: 2) = SGAM ALOKASI (1: 3) = BUKAN
POC YANG DIALOKASI (1: 88968) = 0x0 0_PCT_FULL DIFF (1: 6) = BUKAN PERUBAHAN
ML (1: 7) = BUKAN MIN_LOGGED

Jika saya mencoba menjalankan PAGE DBCC dengan opsi lain, saya mendapatkan kesalahan di bawah ini:

DBCC PAGE dengan opsi 1: Msg 0, Level 11, State 0, Line 0 Terjadi kesalahan parah pada perintah saat ini. Hasilnya, jika ada, harus dibuang.

DBCC PAGE dengan opsi 3: Msg 2514, Level 16, State 5, Line 3 Telah terjadi kesalahan PAGE DBCC: Tipe halaman tidak valid - gaya dump 3 tidak memungkinkan.

UPDATE 2: Berikut adalah beberapa hasil dari DMO sys.dm_db_database_page_allocations:

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 = 92.448
allocated_page_iam_file_id = 1 allocated_page_iam_page_id = 104
allocated_page_file_id = 1 allocated_page_page_id = 92.454
is_allocated = 0 is_iam_page = 0 is_mixed_page_allocation = 0

Eric Cobb
sumber

Jawaban:

8

Sepertinya masalah ini adalah dengan database yang telah menjalankan operasi SHRINK pada mereka. Dalam kasus saya, saya mengambil salinan dari salah satu basis data produksi kami di SQL Server 2014 (yang sudah dienkripsi dengan TDE), menjalankan DBCC SHRINKFILE pada data dan file log, kemudian mengambil cadangan dan mengembalikannya pada SQL baru saya Server 2017. (Alasan menyusut adalah untuk mengurangi ukuran untuk membuat mentransfer cadangan lebih cepat.)

Sebagai tes, saya mengembalikan salinan database yang saya tidak menjalankan DBCC SHRINKFILE, dan tidak memiliki masalah korupsi saat mengompresi cadangan.

Jadi, untuk meringkas, hasil pengujian saya adalah sebagai berikut:

  • Operasi pencadangan / pengembalian normal pada basis data TDE "menyusut" ini bekerja dengan benar di SQL 2017
  • Mengkompresi cadangan dari basis data TDE "menyusut" tampaknya menyebabkan korupsi di tabel sys.sysmultiobjrefs
  • Memampatkan cadangan dari basis data TDE biasa (tidak menjalankan DBCC SHRINKFILE) berfungsi dengan benar dan tidak melaporkan korupsi

Saya tidak tahu apakah ini adalah bug yang dikonfirmasi di SQL Server 2017, tetapi saya telah mengirim temuan saya ke Microsoft untuk diperiksa.

Jadi, moral dari cerita ini adalah: JANGAN MENGISAHKAN DATABASASI ANDA! PERNAH! :)

Eric Cobb
sumber