it-swarm.asia

كيفية معرفة من حذف بعض البيانات SQL Server

كان لدى مديري استفسارًا من أحد العملاء أمس يسأل كيف يمكنهم معرفة من حذف بعض البيانات في قاعدة بيانات SQL Server الخاصة بهم (إنه الإصدار السريع إذا كان ذلك مهمًا).

اعتقدت أن هذا يمكن العثور عليه من سجل المعاملات (شريطة أنه لم يتم اقتطاعه) - هل هذا صحيح؟ وإذا كان الأمر كذلك ، فكيف يمكنك بالفعل العثور على هذه المعلومات؟

29
Matt Wilko

لم أجرب fn_dblog على Express ولكن إذا كان متوفرًا ، فسيمنحك ما يلي عمليات حذف:

SELECT 
    * 
FROM 
    fn_dblog(NULL, NULL) 
WHERE 
    Operation = 'LOP_DELETE_ROWS'

خذ معرف المعاملة للمعاملات التي تهمك وحدد 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]
35
Mark Storey-Smith

إذا كانت قاعدة البيانات في وضع الاسترداد الكامل أو إذا كان لديك نسخ احتياطية من سجل المعاملات ، يمكنك محاولة قراءتها باستخدام قارئات سجل الطرف الثالث.

يمكنك تجربة ApexSQL Log (الإصدار المميز ولكن لديه إصدار تجريبي مجاني) أو الإنقاذ في سجل SQL (الإصدار المجاني ولكن 2000 فقط).

3
Tony Melanik

كيف يمكنهم معرفة من حذف بعض البيانات في قاعدة بيانات SQL Server الخاصة بهم

على الرغم من الرد على هذا ، أردت إضافة أن SQL Server لديه تتبع افتراضي ممكّن ويمكن استخدامه لمعرفة من قام بإسقاط/تغيير الكائنات.

أحداث الكائن

تتضمن أحداث الكائن: كائن تم تغييره ، تم إنشاء الكائن وحذف الكائن

ملاحظة: يحتوي SQL Server بشكل افتراضي على 5 ملفات تتبع ، 20 ميجابايت لكل منها ولا توجد طريقة معتمدة معروفة لتغيير هذا. إذا كان نظامك مشغولاً ، فقد تتدحرج ملفات التتبع بسرعة كبيرة (حتى في غضون ساعات) وقد لا تتمكن من التقاط بعض التغييرات.

يمكن العثور على مثال ممتاز: التتبع الافتراضي في SQL Server - قوة الأداء وتدقيق الأمان

3
Kin Shah

يمكنك تجربة هذا الإجراء للاستعلام عن ملفات النسخ الاحتياطي للسجل والعثور على ملف (ملفات) النسخ الاحتياطي للسجل الذي كانت فيه قيمة معينة لعمود الجدول ما زالت/موجودة حاليًا.

للعثور على المستخدم ، بعد العثور على آخر نسخة احتياطية للسجل ، كانت القيمة الأخيرة موجودة ، يمكنك استعادة قاعدة بيانات حتى ذلك السجل الاحتياطي ثم متابعة إجابة Mark Storey-Smith .

بعض المتطلبات الأساسية

  • معرفة القيم التي تم حذف الأعمدة منها
  • تحت نموذج الاسترداد الكامل وتجري نسخًا احتياطية من السجل
  • لديك تواريخ أو معرفات في النسخ الاحتياطية للسجل ، مثل عند استخدام حل Ola Hallengren

إخلاء المسؤولية

هذا الحل بعيد عن كونه مضادًا للماء ، ويحتاج المزيد من العمل للذهاب إليه.

لم يتم اختباره في بيئات واسعة النطاق ، أو حتى أي بيئات باستثناء بعض الاختبارات الصغيرة. كان التشغيل الحالي على SQL Server 2017.

يمكنك استخدام أدناه الإجراء من محمد عمران الذي قمت بتعديله للعمل مع محتويات النسخ الاحتياطية للسجل بدلاً من محتويات سجل قاعدة البيانات المباشرة.

بهذه الطريقة أنت لا تقوم بعمليات الاستعادة من الناحية الفنية ، ولكن بدلاً من ذلك تقوم بإلقاء محتويات السجل في جدول مؤقت. ربما ستظل بطيئة ، ومنفتحة جدًا على الأخطاء والمشكلات. لكنها يمكن أن تعمل ، من الناحية النظرية.

يستخدم الإجراء المخزن الدالة fn_dump_dblog غير الموثقة لقراءة ملفات السجل.


بيئة الاختبار

ضع في اعتبارك قاعدة البيانات هذه ، حيث نقوم بإدراج بعض الصفوف ، ونأخذ نسختين احتياطيتين للسجل ، وفي النسخة الثالثة للسجل الاحتياطي نحذف جميع الصفوف.

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

تشغيل جديد يبحث عن العدد الصحيح (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
1
Randi Vertongen