Question

Mon patron avait une requête d'un client hier demandant comment ils pourraient savoir qui a supprimé certaines données dans leur base de données SQL Server (il est l'édition expresse si cette question).

Je pensais que cela pourrait être trouvé dans le journal des transactions (à condition qu'il n'a pas été tronquée) - ce correct? Et si oui, comment allez-vous réellement de trouver cette information?

Était-ce utile?

La solution

Je n'ai pas essayé fn_dblog sur Express, mais si elle est disponible, le suivant vous donnera les opérations de suppression:

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

Prenez l'ID de transaction pour les transactions qui vous intéressent et identifier le SID qui a initié la transaction avec:

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

Ensuite, identifier l'utilisateur du SID:

SELECT
    *
FROM 
    sysusers
WHERE
    [sid] = @SID

Edit: Bringing que tous ensemble pour trouver une table sur des suppressions spécifié:

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]

Autres conseils

Si la base de données est en mode de récupération complète ou si vous avez des sauvegardes du journal des transactions, vous pouvez essayer de lire ces tiers à l'aide de lecteurs de journaux.

Vous pouvez essayer (prime mais a un essai gratuit) ApexSQL Connexion ou SQL Log Rescue (gratuit, mais sql 2000 seulement).

  

comment ils pourraient savoir qui a supprimé certaines données dans leur base de données SQL Server

Bien que cette réponse, voulait ajouter que SQL Server a une trace par défaut activée et il peut être utilisé pour savoir qui a abandonné / modifié les objets.

événements objet

événements d'objet comprennent: Objet Altered, Objet créé et objet supprimé

Note: SQL Server par défaut a 5 fichiers de trace, 20 Mo chacun et on ne connaît pas la méthode prise en charge de changer cette situation. Si vous avez un système occupé, les fichiers de trace peuvent rouler beaucoup trop vite (même quelques heures) et vous ne pouvez pas être en mesure d'attraper quelques-uns des changements.

Excellent exemple peut être trouvé: la trace par défaut dans SQL Server - la puissance de l'audit de performance et de sécurité

Vous pouvez essayer cette procédure pour interroger les fichiers de sauvegarde du journal et trouver dans lequel le fichier journal de sauvegarde (s) d'une valeur spécifique d'une colonne d'une table était encore / dernier cadeau.

Pour l'utilisateur, une fois que vous trouverez dans ce journal de sauvegarde la dernière valeur existe, vous pouvez restaurer une base de données jusqu'à ce que la sauvegarde du journal puis suivez Mark Storey-Smith réponse de .

Certaines conditions

  • savoir quelles valeurs dont les colonnes ont été supprimées
  • sont sous le modèle de récupération complète et prennent des sauvegardes du journal
  • vous avez des dates ou des identifiants dans vos sauvegardes de journaux, comme lors de l'utilisation Ola La solution de Hallengren

Disclaimer

Cette solution est loin d'être imperméable à l'eau, et il reste beaucoup de travail pour y entrer.

Il n'a pas été testé sur de grands environnements à grande échelle, ou même des environnements à part quelques petits tests. exécution en cours était sur SQL Server 2017.

Vous pouvez utiliser ci-dessous procédure de Muhammad Imran que j'ai modifié à travailler avec le contenu des sauvegardes log au lieu du contenu du journal d'une base de données en direct.

De cette façon, vous techniquement pas faire des restaurations, mais le dumping au lieu le contenu du journal dans une table temporaire. Ce sera probablement encore lent, et il est très ouvert aux bugs et problèmes. Mais cela pourrait fonctionner, en théorie ™.

La procédure stockée utilise la fonction fn_dump_dblog sans papier pour lire les fichiers journaux.


Test environnement

Considérez cette base de données, où l'on insère des lignes, prendre 2 sauvegardes de journaux, et sur la troisième sauvegarde du journal, nous supprimer toutes les lignes.

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

La procédure

Vous pouvez trouver et télécharger la procédure stockée .

Je ne pouvais pas ajouter ici car il est plus grand que la limite de caractères, et rendrait cette réponse encore moins claire qu'elle ne l'est.

En dehors de cela, vous devriez être en mesure d'exécuter la procédure.

L'exécution de la procédure

Un exemple de cela, quand j'ajoute tous mes fichiers journaux (de 4) à la procédure stockée et exécuter la procédure de recherche valeur1

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

Cela me obtient:

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

Où nous pouvons trouver quand la dernière fois une opération sur value1 est arrivé, la suppression dans log3.trn.

Quelques autres données de test, l'ajout d'une table avec différentes colonnes

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

Modification des noms des fichiers journaux et exécuter à nouveau la procédure

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

Résultat

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

Une nouvelle piste, la recherche de l'entier (2) dans la colonne val3 de dbo.WrongDeletes2

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

Résultat

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

Mark Storey-Smith réponse de

Nous savons maintenant qu'il est arrivé dans le troisième fichier journal, Restaurons jusqu'à ce point:

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

L'exécution de la dernière requête dans sa réponse

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]

Résultat pour moi (sysadmin)

UserName    TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450
Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top