Cara mengetahui siapa yang menghapus beberapa data SQL Server

29

Bos saya memiliki permintaan dari seorang pelanggan kemarin yang menanyakan bagaimana mereka bisa mengetahui siapa yang menghapus beberapa data dalam database SQL Server mereka (ini adalah edisi kilat jika itu penting).

Saya pikir ini dapat ditemukan dari log transaksi (asalkan belum terpotong) - apakah ini benar? Dan jika demikian, bagaimana Anda benar-benar mencari informasi ini?

Matt Wilko
sumber

Jawaban:

35

Saya belum mencoba fn_dblog pada Express tetapi jika tersedia, yang berikut ini akan memberi Anda operasi penghapusan:

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

Ambil ID transaksi untuk transaksi yang Anda minati dan identifikasi SID yang memulai transaksi dengan:

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

Kemudian identifikasi pengguna dari SID:

SELECT
    *
FROM 
    sysusers
WHERE
    [sid] = @SID

Sunting: Membawa semuanya untuk menemukan penghapusan pada tabel yang ditentukan:

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]
Mark Storey-Smith
sumber
Ini memang bekerja dengan SQL express tetapi pada sistem saya hanya menunjukkan transaksi yang terjadi hari ini. Saya tidak berpikir SQL Express memiliki pemotongan log transaksi di luar kotak?
Matt Wilko
5
Jika database Anda dalam model pemulihan sederhana, Anda tidak dapat membuat asumsi tentang berapa lama transaksi tidak aktif akan bertahan di log.
Aaron Bertrand
3
Log transaksi lebih penting daripada opsional. Apa model pemulihan untuk basis data (sederhana atau penuh) dan bagaimana cadangan dikonfigurasi (hanya lengkap atau cadangan log + penuh)?
Mark Storey-Smith
Saya mencuri ini untuk jawaban saya di sini meskipun sedikit refactored untuk menghindari diri bergabung fn_dblog. Satu kelemahannya adalah ia mengembalikan database USERNAME()daripada nama login yang jauh lebih berguna.
Martin Smith
3

Jika database dalam mode pemulihan penuh atau jika Anda memiliki cadangan log transaksi, Anda dapat mencoba membacanya menggunakan pembaca log pihak ketiga.

Anda dapat mencoba ApexSQL Log (premium tetapi memiliki uji coba gratis) atau SQL Log Rescue (gratis tetapi hanya sql 2000).

Tony Melanik
sumber
3

bagaimana mereka bisa mengetahui siapa yang menghapus beberapa data dalam database SQL Server mereka

Meskipun ini dijawab, ingin menambahkan bahwa SQL Server memiliki jejak default diaktifkan dan dapat digunakan untuk mencari tahu siapa yang menjatuhkan / mengubah objek.

Acara objek

Acara objek meliputi: Objek Diubah, Objek Dibuat dan Objek Dihapus

catatan: SQL Server secara default memiliki 5 jejak file, masing-masing 20 MB dan tidak ada metode yang didukung untuk mengubahnya. Jika Anda memiliki sistem yang sibuk, file jejak mungkin bergulir terlalu cepat (bahkan dalam beberapa jam) dan Anda mungkin tidak dapat menangkap beberapa perubahan.

Contoh yang sangat baik dapat ditemukan: Jejak default di SQL Server - kekuatan audit kinerja dan keamanan

Kin Shah
sumber
1

Anda bisa mencoba prosedur ini untuk meminta file cadangan log dan menemukan di mana file cadangan log nilai tertentu dari kolom tabel masih ada / terakhir hadir.

Untuk menemukan pengguna, setelah Anda menemukan dalam cadangan log apa nilai terakhir ada, Anda dapat mengembalikan database hingga cadangan log itu dan kemudian ikuti jawaban Mark Storey-Smith .

Beberapa prasyarat

  • tahu nilai apa dari kolom mana yang dihapus
  • Sedang dalam model pemulihan penuh dan sedang mengambil cadangan log
  • Anda memiliki tanggal atau pengidentifikasi dalam cadangan log Anda, seperti ketika menggunakan solusi Ola Hallengren

Penolakan

Solusi ini jauh dari tahan air, dan masih banyak pekerjaan yang harus dilakukan.

Itu belum diuji pada lingkungan skala besar, atau bahkan lingkungan apa pun selain dari beberapa tes kecil. Jalankan saat ini pada SQL Server 2017.

Anda dapat menggunakan prosedur di bawah ini dari Muhammad Imran yang saya modifikasi untuk bekerja dengan isi cadangan log alih-alih isi dari log basis data langsung.

Dengan cara ini Anda secara teknis tidak melakukan pemulihan, tetapi membuang konten log dalam tabel sementara. Mungkin masih lambat, dan sangat terbuka untuk bug dan masalah. Tapi itu bisa berhasil, dalam teori ™.

Prosedur tersimpan menggunakan fn_dump_dblogfungsi tidak berdokumen untuk membacakan file log.


Lingkungan pengujian

Pertimbangkan basis data ini, tempat kami memasukkan beberapa baris, ambil 2 cadangan log, dan pada cadangan log ketiga kami menghapus semua baris.

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

Prosedur

Anda dapat menemukan dan mengunduh prosedur tersimpan di sini .

Saya tidak dapat menambahkannya di sini karena lebih besar dari batas karakter, dan akan membuat jawaban ini lebih tidak jelas daripada sebelumnya.

Terlepas dari ini, Anda harus dapat menjalankan prosedur.

Menjalankan prosedur

Contoh dari ini, ketika saya menambahkan semua file log saya ( 4) ke prosedur tersimpan & menjalankan prosedur mencari value1

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

Ini membuat saya:

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

Di mana kami dapat menemukan kapan operasi terakhir value1terjadi, penghapusan dalam log3.trn.

Beberapa data uji lagi, menambahkan tabel dengan kolom berbeda

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

Mengubah nama file log & menjalankan prosedur lagi

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

Hasil

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

Jalankan baru, mencari integer ( 2) di val3kolomdbo.WrongDeletes2

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

Hasil

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

Menerapkan jawaban Mark Storey-Smith

Kita tahu sekarang bahwa itu terjadi pada file log ketiga, mari kita pulihkan sampai titik itu:

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

Menjalankan kueri terakhir dalam jawabannya

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]

Hasil untuk saya (sysadmin)

UserName    TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450
Randi Vertongen
sumber