Bazı verileri kimin sildiğini öğrenmek nasıl SQL Server


29

Patronum dün bir müşteriden SQL Server veritabanındaki bazı verileri kimin sildiğini nasıl bulabileceklerini soran bir sorgu aldı (eğer önemliyse ifadedir).

Bunun işlem günlüğünden bulunabileceğini düşündüm (kesilmemesi kaydıyla) - bu doğru mu? Ve eğer öyleyse, aslında bu bilgiyi bulma konusunda nasıl gidiyorsunuz?

Yanıtlar:


35

Express'te fn_dblog komutunu denemedim ama eğer mevcutsa aşağıdakiler size silme işlemlerini verecektir:

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

İlgilendiğiniz işlemlerin işlem kimliğini alın ve işlemi başlatan SID'yi tanımlayın:

SELECT
    [Transaction SID]
FROM
    fn_dblog(NULL, NULL)
WHERE
    [Transaction ID] = @TranID
AND
    [Operation] = 'LOP_BEGIN_XACT'

Ardından kullanıcıyı SID'den tanımlayın:

SELECT
    *
FROM 
    sysusers
WHERE
    [sid] = @SID

Düzenleme: Belirli bir tabloda silmeleri bulmak için hepsini bir araya getirmek:

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]

Bu gerçekten SQL express ile çalışır ancak sistemimde sadece bugün olan işlemleri gösterir. SQL Express'in kutudan bir işlem günlüğü kesmesi olduğunu düşünmedim mi?
Matt Wilko

5
Veritabanınız basit kurtarma modelindeyse, etkin olmayan işlemlerin kayıt defterinde ne kadar süre kalacağı konusunda herhangi bir varsayımda bulunamazsınız.
Aaron Bertrand

3
İşlem günlüğü isteğe bağlı değil, temeldir. Veritabanının kurtarma modeli nedir (basit veya tam) ve yedeklemeler nasıl yapılandırılır (yalnızca tam veya günlük yedekleme + tam)?
Mark Storey-Smith,

Buradaki cevabım için çaldım, ancak kendiliğinden birleşmekten kaçınmak için biraz refaktor olmuş fn_dblog. Bir dezavantajı, USERNAME()çok daha kullanışlı giriş adı yerine veritabanını döndürmesidir .
Martin Smith


3

SQL Server veritabanındaki bazı verileri kimin sildiğini nasıl bulabileceklerini

Bu yanıtlanmasına rağmen, SQL Server'ın varsayılan bir izlemenin etkin olduğunu ve nesneleri kimin düşürdüğünü / değiştirdiğini bulmak için kullanılabilir.

Nesne olayları

Nesne olayları şunları içerir: Nesne Değiştirildi, Nesne Oluşturuldu ve Silinmiş Nesne

not: SQL Server, varsayılan olarak, her biri 20 MB olmak üzere 5 izleme dosyasına sahiptir ve bunu değiştirmek için bilinen desteklenen bir yöntem yoktur. Meşgul bir sisteminiz varsa, izleme dosyaları çok hızlı bir şekilde (saatler içinde bile) devrilebilir ve değişikliklerden bazılarını yakalayamayabilirsiniz.

Mükemmel bir örnek bulunabilir: SQL Server'daki varsayılan izleme - performansın ve güvenlik denetiminin gücü


1

Günlük yedekleme dosyalarını sorgulamak için bu prosedürü deneyebilir ve hangi günlük yedekleme dosyalarında belirli bir tablonun bir sütununun belirli bir değerinin hala / en son olduğunu bulabilirsiniz.

Kullanıcıyı bulmak için, değerin en son hangi günlük yedeklemesinde bulunduğunu öğrendikten sonra, o günlük yedeklemesine kadar bir veritabanını geri yükleyebilir ve ardından Mark Storey-Smith'in cevabını takip edebilirsiniz.

Bazı önkoşullar

  • hangi sütunların hangi değerlerden silindiğini bilmek
  • Tam kurtarma modeli altında ve günlük yedekleme alıyor
  • Günlük yedeklemelerinizde Ola Hallengren'in çözümünü kullanırken olduğu gibi tarihler veya tanımlayıcılar var

feragat

Bu çözüm su geçirmez olmaktan uzak ve çok daha fazla işin yapılması gerekiyor.

Büyük ölçekli ortamlarda veya birkaç küçük test dışında bile herhangi bir ortamda test edilmemiştir. Geçerli çalıştırma, SQL Server 2017'de yapıldı.

Aşağıdaki kullanabilirsiniz prosedür gelen Muhammed İmran ben içeriğiyle çalışmalarına modifiye olduğu günlüğü yedekleri yerine canlı bir veritabanının log içeriğinin.

Bu yolla teknik olarak geri yükleme yapmıyorsunuz, bunun yerine günlük içeriğini geçici bir tabloya atıyorsunuz. Muhtemelen hala yavaş olacak ve böcek ve konulara çok açık. Fakat teorik olarak işe yarayabilir ™.

Saklı yordam fn_dump_dblog, günlük dosyalarını okumak için belgelenmemiş işlevi kullanır .


Test ortamı

Bazı satırları eklediğimiz bu veritabanını düşünün, 2 günlük yedeklemesi alın ve üçüncü günlük yedeklemesinde tüm satırları silin.

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

Prosedür

Saklı yordamı burada bulabilir ve indirebilirsiniz .

Karakter sınırlamasından daha büyük olduğu için buraya ekleyemedim ve bu cevabı olduğundan daha az net bir hale getirecekti.

Bunun dışında prosedürü uygulayabilmelisiniz.

İşlemi yürütmek

Buna bir örnek, tüm günlük dosyalarımı ( 4) saklı yordamlara eklediğimde ve değer1'i arayan yordamı çalıştırdığımda

EXEC dbo.Recover_Deleted_Data_Proc  @Database_Name= 'WrongDeletesDatabase',
                                    @SchemaName_n_TableName= 'dbo.WrongDeletes', 
                                    @SearchString = 'value1', 
                                    @SearchColumn = 'val',
                                    @LogBackupFolder ='C:\temp\Logs\'

Bu beni alır:

ID  val LogFileName
1   value1  c:\temp\Logs\log3.trn
1   value1  c:\temp\Logs\log1.trn

Bir işlemin en son ne zaman gerçekleştiğini bulabiliriz value1, sil log3.trn.

Biraz daha test verisi, farklı sütunlara sahip bir tablo ekleme

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

Günlük dosyası adlarını değiştirme ve prosedürü tekrar yürütme

EXEC dbo.Recover_Deleted_Data_Proc  @Database_Name= 'WrongDeletesDatabase',
                                    @SchemaName_n_TableName= 'dbo.WrongDeletes', 
                                    @SearchString = 'value1', 
                                    @SearchColumn = 'val',
                                    @LogBackupFolder ='C:\temp\Logs\'

Sonuç

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

Sütunundaki tamsayıyı ( 2) arayan yeni bir çalışmaval3dbo.WrongDeletes2

EXEC dbo.Recover_Deleted_Data_Proc  @Database_Name= 'WrongDeletesDatabase',
                                    @SchemaName_n_TableName= 'dbo.WrongDeletes2', 
                                    @SearchString = '2', 
                                    @SearchColumn = 'Val3',
                                    @LogBackupFolder ='C:\temp\Logs\'

Sonuç

Anotherval  Val3    Wow LogFileName
value2  2   c   c:\temp\Logs\log2.trn
value2  2   c   c:\temp\Logs\log3.trn

Uygulama Mark Katlı-Smith'in cevabını

Şimdi üçüncü günlük dosyasında olduğunu biliyoruz, o noktaya kadar geri yükleyelim:

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

Cevabındaki son sorguyu çalıştırma

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]

Benim için sonuç (sysadmin)

UserName    TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.