답변:
Express에서 fn_dblog를 시도하지 않았지만 사용 가능한 경우 다음 작업을 수행하면 삭제 작업이 수행됩니다.
SELECT
*
FROM
fn_dblog(NULL, NULL)
WHERE
Operation = 'LOP_DELETE_ROWS'
관심있는 거래의 거래 ID를 가져 와서 다음과 같이 거래를 시작한 SID를 식별하십시오.
SELECT
[Transaction SID]
FROM
fn_dblog(NULL, NULL)
WHERE
[Transaction ID] = @TranID
AND
[Operation] = 'LOP_BEGIN_XACT'
그런 다음 SID에서 사용자를 식별하십시오.
SELECT
*
FROM
sysusers
WHERE
[sid] = @SID
편집 : 지정된 테이블에서 삭제를 찾기 위해 모두 모으십시오.
DECLARE @TableName sysname
SET @TableName = 'dbo.Table_1'
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]
fn_dblog
. 한 가지 단점은 USERNAME()
훨씬 더 유용한 로그인 이름 대신 데이터베이스를 반환 한다는 것입니다.
데이터베이스가 전체 복구 모드이거나 트랜잭션 로그 백업이있는 경우 타사 로그 리더를 사용하여 데이터베이스를 읽으려고 시도 할 수 있습니다.
ApexSQL Log (프리미엄이지만 무료 평가판 사용) 또는 SQL Log Rescue (무료이지만 SQL 2000 만 해당)를 사용해 볼 수 있습니다 .
SQL Server 데이터베이스에서 일부 데이터를 삭제 한 사람을 찾는 방법
이것이 대답되었지만 SQL Server에 기본 추적이 활성화되어 있으며 누가 개체를 삭제 / 변경했는지 확인할 수 있습니다.
객체 이벤트
오브젝트 이벤트에는 오브젝트 변경, 오브젝트 작성 및 오브젝트 삭제가 포함됩니다.
참고 : SQL Server에는 기본적으로 5 개의 추적 파일 (각 20MB)이 있으며이를 지원하는 알려진 방법은 없습니다. 사용중인 시스템이있는 경우 추적 파일이 너무 빨리 롤오버되어 (몇 시간 내에도) 일부 변경 사항을 포착하지 못할 수 있습니다.
탁월한 예를 찾을 수 있습니다. SQL Server의 기본 추적-성능 및 보안 감사의 힘
이 절차를 수행하여 로그 백업 파일을 쿼리하고 테이블 열의 특정 값이 아직 / 마지막으로 존재하는 로그 백업 파일을 찾을 수 있습니다.
사용자를 찾기 위해 마지막으로 존재했던 로그 백업 값을 찾은 후 해당 로그 백업까지 데이터베이스를 복원 한 다음 Mark Storey-Smith 의 답변 을 따를 수 있습니다.
일부 전제 조건
기권
이 솔루션은 방수 기능과는 거리가 멀고 더 많은 작업이 필요합니다.
대규모 환경이나 몇 가지 작은 테스트 이외의 환경에서는 테스트되지 않았습니다. 현재 실행은 SQL Server 2017에서 수행되었습니다.
라이브 데이터베이스 로그의 내용 대신 로그 백업 의 내용으로 작업하도록 수정 한 Muhammad Imran의 아래 절차 를 사용할 수 있습니다 .
이렇게하면 기술적으로 복원을 수행하지 않고 임시 테이블에 로그 내용을 덤프합니다. 아마 여전히 느릴 것이며 버그와 이슈에 매우 개방적입니다. 그러나 이론 상으로는 효과가있을 수 있습니다.
저장 프로시 저는 문서화되지 않은 fn_dump_dblog
기능을 사용 하여 로그 파일을 읽습니다.
테스트 환경
일부 데이터베이스를 삽입하고 2 개의 로그 백업을 수행하고 3 번째 로그 백업에서는 모든 행을 삭제하는이 데이터베이스를 고려하십시오.
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
)을 저장 프로 시저에 추가하고 value1을 찾는 프로 시저를 실행할 때
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
열 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]
나에 대한 결과 (sysadmin)
UserName TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450