Günlük yedekleme dosyalarını sorgulamak için bu prosedürü deneyebilir ve hangi günlük yedekleme dosyalarında belirli bir tablonun bir sütununun belirli bir değerinin hala / en son olduğunu bulabilirsiniz.
Kullanıcıyı bulmak için, değerin en son hangi günlük yedeklemesinde bulunduğunu öğrendikten sonra, o günlük yedeklemesine kadar bir veritabanını geri yükleyebilir ve ardından Mark Storey-Smith'in cevabını takip edebilirsiniz.
Bazı önkoşullar
- hangi sütunların hangi değerlerden silindiğini bilmek
- Tam kurtarma modeli altında ve günlük yedekleme alıyor
- Günlük yedeklemelerinizde Ola Hallengren'in çözümünü kullanırken olduğu gibi tarihler veya tanımlayıcılar var
feragat
Bu çözüm su geçirmez olmaktan uzak ve çok daha fazla işin yapılması gerekiyor.
Büyük ölçekli ortamlarda veya birkaç küçük test dışında bile herhangi bir ortamda test edilmemiştir. Geçerli çalıştırma, SQL Server 2017'de yapıldı.
Aşağıdaki kullanabilirsiniz prosedür gelen Muhammed İmran ben içeriğiyle çalışmalarına modifiye olduğu günlüğü yedekleri yerine canlı bir veritabanının log içeriğinin.
Bu yolla teknik olarak geri yükleme yapmıyorsunuz, bunun yerine günlük içeriğini geçici bir tabloya atıyorsunuz. Muhtemelen hala yavaş olacak ve böcek ve konulara çok açık. Fakat teorik olarak işe yarayabilir ™.
Saklı yordam fn_dump_dblog
, günlük dosyalarını okumak için belgelenmemiş işlevi kullanır .
Test ortamı
Bazı satırları eklediğimiz bu veritabanını düşünün, 2 günlük yedeklemesi alın ve üçüncü günlük yedeklemesinde tüm satırları silin.
CREATE DATABASE WrongDeletesDatabase
GO
USE WrongDeletesDatabase
GO
BACKUP DATABASE WrongDeletesDatabase TO DISK ='c:\temp\Full.bak'
ALTER DATABASE WrongDeletesDatabase SET RECOVERY FULL
GO
CREATE TABLE dbo.WrongDeletes(ID INT, val varchar(255))
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (1,'value1')
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log1.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (2,'value2')
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log2.trn'
GO
DELETE FROM dbo.WrongDeletes
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log3.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (3,'value3')
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log4.trn'
GO
Prosedür
Saklı yordamı burada bulabilir ve indirebilirsiniz .
Karakter sınırlamasından daha büyük olduğu için buraya ekleyemedim ve bu cevabı olduğundan daha az net bir hale getirecekti.
Bunun dışında prosedürü uygulayabilmelisiniz.
İşlemi yürütmek
Buna bir örnek, tüm günlük dosyalarımı ( 4
) saklı yordamlara eklediğimde ve değer1'i arayan yordamı çalıştırdığımda
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Bu beni alır:
ID val LogFileName
1 value1 c:\temp\Logs\log3.trn
1 value1 c:\temp\Logs\log1.trn
Bir işlemin en son ne zaman gerçekleştiğini bulabiliriz value1
, sil log3.trn
.
Biraz daha test verisi, farklı sütunlara sahip bir tablo ekleme
CREATE TABLE dbo.WrongDeletes2(Wow varchar(255), Anotherval varchar(255),Val3 int)
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (1,'value1')
INSERT INTO dbo.WrongDeletes2(wOw,Anotherval,Val3)
VALUES ('b','value1',1)
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log1_1.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (2,'value2')
INSERT INTO dbo.WrongDeletes2(wOw,Anotherval,Val3)
VALUES ('c','value2',2)
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log2_1.trn'
GO
DELETE FROM dbo.WrongDeletes
DELETE FROM dbo.WrongDeletes2
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log3_1.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (3,'value3')
INSERT INTO dbo.WrongDeletes2(wOw,Anotherval,Val3)
VALUES ('d','value3',3)
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log4_1.trn'
GO
Günlük dosyası adlarını değiştirme ve prosedürü tekrar yürütme
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Sonuç
ID val LogFileName
1 value1 c:\temp\Logs\log1_1.trn
1 value1 c:\temp\Logs\log3_1.trn
1 value1 c:\temp\Logs\log3_1.trn
Sütunundaki tamsayıyı ( 2
) arayan yeni bir çalışmaval3
dbo.WrongDeletes2
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes2',
@SearchString = '2',
@SearchColumn = 'Val3',
@LogBackupFolder ='C:\temp\Logs\'
Sonuç
Anotherval Val3 Wow LogFileName
value2 2 c c:\temp\Logs\log2.trn
value2 2 c c:\temp\Logs\log3.trn
Uygulama Mark Katlı-Smith'in cevabını
Şimdi üçüncü günlük dosyasında olduğunu biliyoruz, o noktaya kadar geri yükleyelim:
USE master
GO
ALTER DATABASE WrongDeletesDatabase SET OFFLINE WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE WrongDeletesDatabase SET ONLINE
GO
RESTORE DATABASE WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\Full.bak' WITH NORECOVERY,REPLACE
RESTORE LOG WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\log1.trn' WITH NORECOVERY
RESTORE LOG WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\log2.trn' WITH NORECOVERY
RESTORE LOG WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\log3.trn' WITH RECOVERY
GO
USE WrongDeletesDatabase
GO
Cevabındaki son sorguyu çalıştırma
SELECT
u.[name] AS UserName
, l.[Begin Time] AS TransactionStartTime
FROM
fn_dblog(NULL, NULL) l
INNER JOIN
(
SELECT
[Transaction ID]
FROM
fn_dblog(NULL, NULL)
WHERE
AllocUnitName LIKE @TableName + '%'
AND
Operation = 'LOP_DELETE_ROWS'
) deletes
ON deletes.[Transaction ID] = l.[Transaction ID]
INNER JOIN
sysusers u
ON u.[sid] = l.[Transaction SID]
Benim için sonuç (sysadmin)
UserName TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450