Вы можете попробовать эту процедуру, чтобы запросить файлы резервных копий журналов и найти, в каких файлах резервных копий журналов конкретное значение столбца таблицы было еще / последним.
Чтобы найти пользователя, после того, как вы найдете в какой резервной копии журнала значение, которое существовало в последний раз, вы можете восстановить базу данных до этой резервной копии журнала и затем следовать ответу Марка Стори-Смита .
Некоторые предпосылки
- знать, какие значения из каких столбцов были удалены
- Находятся под моделью полного восстановления и делают резервные копии журналов
- у вас есть даты или идентификаторы в резервных копиях журналов, например, при использовании решения Олы Хелленгрен
отказ
Это решение далеко не водонепроницаемо, и для его выполнения требуется гораздо больше работы.
Он не был протестирован в крупномасштабных средах или даже в любых средах, за исключением нескольких небольших тестов. Текущий запуск был на SQL Server 2017.
Вы можете использовать приведенную ниже процедуру от Мухаммеда Имрана, которую я модифицировал для работы с содержимым резервных копий журналов вместо содержимого журнала активной базы данных.
Таким образом, технически вы не выполняете восстановление, а просто записываете содержимое журнала во временную таблицу. Это, вероятно, все еще будет медленным и очень открытым для ошибок и проблем. Но это может сработать, в теории ™.
Хранимая процедура использует недокументированную fn_dump_dblog
функцию для считывания файлов журнала.
Тестовая среда
Рассмотрим эту базу данных, где мы вставляем несколько строк, делаем 2 резервных копии журнала, а в третьей резервной копии журнала мы удаляем все строки.
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
Процедура
Вы можете найти и скачать хранимую процедуру здесь .
Я не мог бы добавить это здесь, так как он больше, чем ограничение по количеству символов, и сделал бы этот ответ еще менее ясным, чем он есть.
Помимо этого, вы должны быть в состоянии запустить процедуру.
Запуск процедуры
Пример этого - когда я добавляю все свои файлы журналов ( 4
) в хранимую процедуру и запускаю процедуру в поисках значения1
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Это получает меня:
ID val LogFileName
1 value1 c:\temp\Logs\log3.trn
1 value1 c:\temp\Logs\log1.trn
Где мы можем найти, когда в последний раз произошла операция value1
, удалить в log3.trn
.
Еще несколько тестовых данных, добавление таблицы с разными столбцами
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
Изменение имен файлов журнала и повторное выполнение процедуры
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes',
@SearchString = 'value1',
@SearchColumn = 'val',
@LogBackupFolder ='C:\temp\Logs\'
Результат
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
Новый прогон, ищущий integer ( 2
) в val3
столбцеdbo.WrongDeletes2
EXEC dbo.Recover_Deleted_Data_Proc @Database_Name= 'WrongDeletesDatabase',
@SchemaName_n_TableName= 'dbo.WrongDeletes2',
@SearchString = '2',
@SearchColumn = 'Val3',
@LogBackupFolder ='C:\temp\Logs\'
Результат
Anotherval Val3 Wow LogFileName
value2 2 c c:\temp\Logs\log2.trn
value2 2 c c:\temp\Logs\log3.trn
Применяя ответ Марка Стори-Смита
Теперь мы знаем, что это произошло в третьем файле журнала, давайте восстановим до этого момента:
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
Выполнение последнего запроса в своем ответе
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]
Результат для меня (сисадмин)
UserName TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450