Pencadangan log transaksi SQL Server: menguji apakah log ekor mengikuti pencadangan log yang terakhir diketahui

11

Kami menggunakan SQL Server dengan mode pemulihan penuh. Dengan cadangan lengkap dan serangkaian cadangan log, kami ingin dapat memeriksa apakah rantai log selesai dari cadangan penuh terakhir hingga log ekor saat ini. (Tanpa benar-benar mengembalikan cadangan ini; tujuannya di sini adalah untuk menguji konsistensi cadangan.)

Saya sudah tahu bagaimana melakukan ini untuk cadangan yang ada: menggunakan RESTORE HEADERONLY Saya mendapatkan FirstLSN dan LastLSN dari setiap file, yang dapat dibandingkan untuk file yang berurutan, untuk menentukan apakah mereka kompatibel.

Namun, saya tidak tahu bagaimana memeriksa apakah log ekor mengikuti cadangan log terakhir.

Jika saya memiliki FirstLSN dari log ekor, saya bisa membandingkannya dengan LastLSN dari cadangan log terakhir. Tetapi bagaimana saya bisa mendapatkan FirstLSN dari log ekor?

Saya memerlukan solusi yang bekerja dari SQL Server 2005 ke atas (idealnya menggunakan t-sql). Sejauh ini, saya telah mencari Google tetapi tidak berhasil. Btw. Saya pertama kali memposting ini di stackoverflow; tetapi bermigrasi di sini karena ditandai di luar topik di sana.

EDIT

Saya mencoba dua solusi yang diberikan pada contoh kecil (SQL Server 2005, 9.0.5057):

BACKUP DATABASE TestDb TO DISK = 'C:\temp\backup test\Full.bak' 

-- fire some update queries

BACKUP LOG TestDb TO DISK =  'C:\temp\backup test\Log1.bak' 

-- fire both queries from the provided answers: 
-- Martin Smith's answer yields: 838886656088920652852608
-- Shawn Melton's answer yields: 46000000267600001

RESTORE HEADERONLY FROM DISK = 'C:\temp\backup test\Log1.bak'  
-- yields: 46000000267600001

Jadi tampaknya yang pertama dimatikan oleh beberapa urutan besarnya.

Saya kemudian melakukan tes yang sama pada SQL 2008 SP1 (10.00.2531), di mana kedua kueri menghasilkan jawaban yang benar.

Andreas
sumber
Saya sudah melakukan riset karena ini pertanyaan yang menarik, tapi saya tidak terlalu jauh. Saya tidak yakin SQL mendukung hal ini.
Katherine Villyard
1
Saya yakin ada cara untuk memverifikasi ini, mungkin menggunakan LSN bukan cara untuk melakukannya. Saya akan memberi hadiah pada pertanyaan dalam beberapa jam, pertanyaan ini perlu lebih banyak dilihat ..

Jawaban:

12

Saya menoleh ke salinan SQL Server 2008 Internal dan DMV sys.database_recovery_status ditunjukkan untuk menemukan LSN pertama dari cadangan log berikutnya. Yang terjadi dengan BOL, kolom last_log_backup_lsnmemberi Anda:

Nomor urut log dari cadangan log terbaru. Ini adalah LSN akhir dari cadangan log sebelumnya dan LSN awal dari cadangan log berikutnya.
NULL = Tidak ada cadangan log. Database sedang offline atau database tidak akan mulai.

Hanya untuk menyebutkan juga bahwa Kalen juga memunculkan poin bahwa Anda akan mendapatkan nilai NULL jika database berada dalam mode pemulihan SEDERHANA (mode autotruncate) atau jika tidak ada cadangan log.

Tetapi bagaimana saya bisa mendapatkan FirstLSN dari log ekor?

Tanpa benar-benar mencadangkan log ekor dari database (tidak memiliki contoh uji untuk mencoba ini), Anda dapat menyimpulkan bahwa nilai yang dikembalikan pada kolom yang disebutkan akan menjadi LSN pertama dari cadangan log berikutnya, dalam kasus Anda ekor.

Jadi, mengeksekusi yang berikut ini akan mengembalikan nilai yang saya yakin Anda cari:


SELECT 
   last_log_backup_lsn
FROM 
   sys.database_recovery_status
WHERE 
   databse_id = DB_ID('MyDb')

DMV ini tersedia mulai dari SQL 2005.

EDIT
Kecuali Anda membaca tautan BOL, harap perhatikan bahwa DMV ini hanya akan mengembalikan nilai ke database yang sedang online, atau dibuka sebagai referensi BOL. Jika terjadi kegagalan yang mengharuskan Anda untuk mengambil cadangan log ekor dari database Anda tidak akan dapat memverifikasi nilai ini melalui kode di atas kecuali database dapat diakses; yang dalam kegagalan itu mungkin tidak akan terjadi.


sumber
Hasil kueri ini tampaknya benar.
Andreas
Jelas terlihat benar bagi saya. Last_log_backup_lsn sama dengan first_lsn dari ujung log. Jadi, jika Anda memiliki file log yang akan dipulihkan dengan last_lsn sama dengan last_log_backup_lsn dari kode Shawn, maka Anda tahu bahwa Anda memiliki cadangan hingga log ekor. (Tentu saja itu hanya dijamin benar pada saat permintaan, saat berikutnya cadangan log baru dapat dimulai.)
RLF
@RLF menambahkan catatan tambahan karena ini juga akan benar jika database tidak dapat diakses. Ini sebenarnya bukan solusi yang layak untuk digunakan ketika perlu mengimplementasikan rencana pemulihan bencana Anda. Murni untuk latihan di atas meja atau menguji rencana Anda.
6

Sesuatu seperti yang berikut ini harus melakukannya.

WITH LSN_CTE
AS
(
SELECT TOP 1
       LEFT( LogRecords.[Current LSN], 8 )          AS Part1,
       SUBSTRING( LogRecords.[Current LSN], 10, 8 ) AS Part2,
       RIGHT( LogRecords.[Current LSN], 4 )         AS Part3
FROM   sys.fn_dblog(NULL,NULL) AS LogRecords
ORDER BY [Current LSN]
)
SELECT CAST( CAST( CONVERT( varbinary, Part1, 2 ) AS int ) AS varchar ) +
       RIGHT( '0000000000' + CAST( CAST( CONVERT( varbinary, Part2, 2 ) AS int ) AS varchar ), 10 ) +
       RIGHT( '00000'      + CAST( CAST( CONVERT( varbinary, Part3, 2 ) AS int ) AS varchar ), 5 ) AS [Converted LSN]
FROM   LSN_CTE

Menggunakan kode konversi ke desimal dari artikel ini .

The ORDER BY [Current LSN]juga mungkin overhead yang sama sekali tidak perlu. Saya tidak yakin. Hasil dari fungsi ini sepertinya selalu dalam urutan LSN dan saya kira itu hanya membaca log secara berurutan tetapi untuk berjaga-jaga ...

Martin Smith
sumber
@ MartinSmith: fn_dblogsepertinya tidak didokumentasikan dengan sangat baik. Saya menganggap hasilnya selalu berlaku untuk database saat ini (karena tidak ada WHERE DbName = 'XXX'dalam cuplikan)?
Andreas
@ Andreas - Ya, itu tidak berdokumen. Dan ya itu mengembalikan informasi dari log dari database saat ini.
Martin Smith
lihat edit saya ke pertanyaan awal. Jumlah yang dikembalikan oleh snippet Anda jauh lebih besar daripada LSN dari cadangan terkini dari DB yang sama.
Andreas
@Andreas - Aneh. Saya hanya mencobanya pada tes DB tunggal dan itu bekerja dengan benar. Tidak yakin di mana kesalahannya. Versi SQL Server apa yang Anda jalankan ini? The CONVERTdengan gaya parameter 2mungkin menjadi masalahnya.
Martin Smith
(Meskipun jawaban Shawn tampaknya lebih disukai daripada yang ini)
Martin Smith