วิธีค้นหาว่าใครลบข้อมูล SQL Server บ้าง


29

เจ้านายของฉันมีแบบสอบถามจากลูกค้าเมื่อวานนี้ถามว่าพวกเขาสามารถค้นหาผู้ที่ลบข้อมูลบางอย่างในฐานข้อมูล SQL Server ของพวกเขา (เป็นรุ่นด่วนหากเรื่องนั้น)

ฉันคิดว่าสิ่งนี้สามารถพบได้จากบันทึกธุรกรรม (หากไม่ได้ถูกตัดทอน) - ถูกต้องหรือไม่ และถ้าเป็นเช่นนั้นคุณจะไปหาข้อมูลนี้ได้อย่างไร?

คำตอบ:


35

ฉันไม่ได้ลอง fn_dblog บน Express แต่ถ้ามีอยู่ต่อไปนี้จะทำให้คุณลบการดำเนินการ:

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]

สิ่งนี้ใช้ได้กับ SQL express แต่ในระบบของฉันจะแสดงเฉพาะธุรกรรมที่เกิดขึ้นวันนี้เท่านั้น ฉันไม่คิดว่า SQL Express มีการตัดทอนบันทึกธุรกรรมออกจากกล่องหรือไม่?
Matt Wilko

5
หากฐานข้อมูลของคุณอยู่ในรูปแบบการกู้คืนอย่างง่ายคุณไม่สามารถทำการสันนิษฐานได้ว่าธุรกรรมที่ไม่ได้ใช้งานจะใช้เวลานานเท่าใดในบันทึก
Aaron Bertrand

3
บันทึกธุรกรรมเป็นข้อมูลเบื้องต้นแทนที่จะเป็นทางเลือก รูปแบบการกู้คืนสำหรับฐานข้อมูล (แบบง่ายหรือแบบเต็ม) คืออะไรและมีการกำหนดค่าการสำรองข้อมูลอย่างไร (แบบเต็มเท่านั้นหรือการสำรองข้อมูลแบบเต็ม +)
Mark Storey-Smith

ฉันขโมยนี้สำหรับคำตอบของฉันที่นี่แม้ว่า refactored fn_dblogบิตเพื่อหลีกเลี่ยงการเข้าร่วมในตนเอง ข้อเสียอย่างหนึ่งคือมันส่งคืนฐานข้อมูลUSERNAME()มากกว่าชื่อล็อกอินที่มีประโยชน์มากกว่า
Martin Smith

3

หากฐานข้อมูลอยู่ในโหมดการกู้คืนแบบเต็มหรือถ้าคุณมีการสำรองข้อมูลบันทึกธุรกรรมคุณสามารถลองอ่านสิ่งเหล่านี้ได้โดยใช้ตัวอ่านบันทึกของบุคคลที่สาม

คุณสามารถลองใช้ApexSQL Log (พรีเมียม แต่มีรุ่นทดลองใช้ฟรี) หรือSQL Log Rescue (ฟรียกเว้น sql 2000 เท่านั้น)


3

วิธีที่พวกเขาสามารถค้นหาผู้ที่ลบข้อมูลบางอย่างในฐานข้อมูล SQL Server ของพวกเขา

แม้ว่าจะได้รับคำตอบนี้ต้องการเพิ่มว่า SQL Server มีการเปิดใช้งานการติดตามเริ่มต้นและสามารถใช้เพื่อค้นหาผู้ที่หล่น / เปลี่ยนแปลงวัตถุ

เหตุการณ์วัตถุ

เหตุการณ์ของวัตถุ ได้แก่ : การเปลี่ยนแปลงวัตถุการสร้างวัตถุและการลบวัตถุ

บันทึก:โดยค่าเริ่มต้น SQL Server จะมีไฟล์การติดตาม 5 ไฟล์แต่ละไฟล์มี 20 MB และไม่มีวิธีการใดที่รองรับการเปลี่ยนแปลงนี้ หากคุณมีระบบไม่ว่างไฟล์การติดตามอาจหมุนเร็วเกินไป (แม้ภายในไม่กี่ชั่วโมง) และคุณอาจไม่สามารถตรวจจับการเปลี่ยนแปลงบางอย่างได้

ตัวอย่างที่ยอดเยี่ยมสามารถพบได้: การติดตามเริ่มต้นใน SQL Server - พลังของประสิทธิภาพและการตรวจสอบความปลอดภัย


1

คุณสามารถลองโพรซีเดอร์นี้เพื่อเคียวรีไฟล์บันทึกการสำรองข้อมูลและค้นหาไฟล์บันทึกการสำรองที่มีค่าเฉพาะของคอลัมน์ของตารางที่ยังคงอยู่ / ล่าสุด

ในการค้นหาผู้ใช้หลังจากที่คุณพบว่ามีการสำรองข้อมูลบันทึกค่าที่มีอยู่ล่าสุดคุณสามารถคืนค่าฐานข้อมูลจนกว่าจะมีการสำรองข้อมูลบันทึกนั้นแล้วทำตามคำตอบของMark Storey-Smith

ข้อกำหนดเบื้องต้นบางอย่าง

  • รู้ค่าที่ลบคอลัมน์ใด
  • อยู่ภายใต้รูปแบบการกู้คืนแบบเต็มและกำลังทำการสำรองข้อมูลบันทึก
  • คุณมีวันที่หรือตัวระบุในการสำรองข้อมูลบันทึกของคุณเช่นเมื่อใช้โซลูชันของ Ola Hallengren

คำปฏิเสธ

วิธีแก้ปัญหานี้อยู่ไกลจากกันน้ำและจำเป็นต้องทำงานมากกว่านี้

มันไม่ได้รับการทดสอบในสภาพแวดล้อมขนาดใหญ่หรือแม้กระทั่งสภาพแวดล้อมใด ๆ นอกเหนือจากการทดสอบเล็กน้อย การดำเนินการปัจจุบันอยู่บน SQL Server 2017

คุณสามารถใช้ขั้นตอนด้านล่างจากMuhammad Imranที่ฉันแก้ไขเพื่อทำงานกับเนื้อหาของการสำรองข้อมูลบันทึกแทนเนื้อหาของบันทึกของฐานข้อมูลสด

วิธีนี้คุณจะไม่ทำการกู้คืนทางเทคนิค แต่จะทิ้งเนื้อหาของบันทึกในตารางชั่วคราวแทน มันอาจจะยังช้าและเปิดรับข้อบกพร่องและปัญหาได้มาก แต่มันสามารถใช้งานได้ในทางทฤษฎี™

กระบวนงานที่เก็บไว้ใช้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

ที่เราสามารถหาเมื่อเวลาที่ผ่านมาการดำเนินการเกี่ยวกับที่เกิดขึ้นในการลบvalue1log3.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

ใช้คำตอบของMark Storey-Smith

เรารู้แล้วว่ามันเกิดขึ้นในล็อกไฟล์ที่สามมาคืนค่ากันจนถึงจุดนั้น:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.