Bạn có thể thử quy trình này để truy vấn các tệp sao lưu nhật ký và tìm trong đó (các) tệp sao lưu nhật ký một giá trị cụ thể của một cột của bảng vẫn còn / hiện tại.
Để tìm người dùng, sau khi bạn tìm thấy bản sao lưu nhật ký giá trị tồn tại lần cuối, bạn có thể khôi phục cơ sở dữ liệu cho đến khi sao lưu nhật ký đó và sau đó làm theo câu trả lời của Mark Storey-Smith .
Một số điều kiện tiên quyết
- biết những giá trị nào từ các cột đã bị xóa
- Đang trong mô hình khôi phục đầy đủ và đang thực hiện sao lưu nhật ký
- bạn có ngày hoặc số nhận dạng trong bản sao lưu nhật ký của mình, chẳng hạn như khi sử dụng giải pháp của Ola Hallengren
Khước từ
Giải pháp này là không thấm nước, và nhiều công việc cần phải đi vào nó.
Nó chưa được thử nghiệm trên các môi trường quy mô lớn, hoặc thậm chí bất kỳ môi trường nào ngoài một vài thử nghiệm nhỏ. Chạy hiện tại là trên SQL Server 2017.
Bạn có thể sử dụng quy trình dưới đây từ Muhammad Imran mà tôi đã sửa đổi để làm việc với nội dung của bản sao lưu nhật ký thay vì nội dung của nhật ký cơ sở dữ liệu trực tiếp.
Bằng cách này, về mặt kỹ thuật, bạn không thực hiện khôi phục mà thay vào đó bỏ nội dung nhật ký vào một bảng tạm thời. Nó có thể vẫn sẽ chậm, và rất cởi mở với các lỗi và vấn đề. Nhưng nó có thể hoạt động, theo lý thuyết ™.
Thủ tục được lưu trữ sử dụng fn_dump_dblog
chức năng không có giấy tờ để đọc các tệp nhật ký.
Môi trường thử nghiệm
Hãy xem xét cơ sở dữ liệu này, nơi chúng tôi chèn một số hàng, lấy 2 bản sao lưu nhật ký và trên bản sao lưu nhật ký thứ ba, chúng tôi xóa tất cả các hàng.
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
Thủ tục
Bạn có thể tìm và tải về các thủ tục được lưu trữ ở đây .
Tôi không thể thêm nó ở đây vì nó lớn hơn giới hạn ký tự và sẽ làm cho câu trả lời này thậm chí còn ít rõ ràng hơn nó.
Ngoài ra, bạn sẽ có thể chạy các thủ tục.
Chạy thủ tục
Một ví dụ về điều này, khi tôi thêm tất cả các tệp nhật ký của mình ( 4
) vào thủ tục được lưu trữ và chạy thủ tục tìm giá trị1
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Điều này giúp tôi:
ID val LogFileName
1 value1 c:\temp\Logs\log3.trn
1 value1 c:\temp\Logs\log1.trn
Nơi chúng ta có thể tìm thấy khi lần cuối hoạt động value1
xảy ra, xóa tronglog3.trn
.
Một số dữ liệu thử nghiệm khác, thêm một bảng với các cột khác nhau
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
Thay đổi tên tệp nhật ký và thực hiện lại quy trình
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Kết quả
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
Một lần chạy mới, tìm kiếm số nguyên ( 2
) trong val3
cột củadbo.WrongDeletes2
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes2',
@SearchString = '2',
@SearchColumn = 'Val3',
@LogBackupFolder ='C:\temp\Logs\'
Kết quả
Anotherval Val3 Wow LogFileName
value2 2 c c:\temp\Logs\log2.trn
value2 2 c c:\temp\Logs\log3.trn
Áp dụng Mark Storey-Smith câu trả lời của
Bây giờ chúng ta biết rằng nó đã xảy ra trong tệp nhật ký thứ ba, hãy khôi phục cho đến thời điểm đó:
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
Chạy truy vấn cuối cùng trong câu trả lời của anh ấy
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]
Kết quả cho tôi (sysadmin)
UserName TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450