0

There is SQL Server 2012 database that is used by three different applications. In that database there is a table that contains ~500k rows and for some mysterious reason this table gets emptied every now and then. I think this is possibly caused by:

  • A delete query without a where clause
  • A delete query in a loop gone wild

I am trying to locate the cause of this issue by reviewing code but no joy. I need an alternate strategy. I think I can use triggers to detect what/why all rows get deleted but I am not sure how to go about this. So:

  • Can I use triggers to check if a query is attempting to delete all rows?
  • Can I use triggers to log the problematic query and the application that issues that query?
  • Can I use triggers to log such actions into a text file/database table/email?
  • Is there a better way?
Salman A
  • 262,204
  • 82
  • 430
  • 521
  • You could create a trigger to log/alert if the total number of rows to be deleted exceeds a certain number. That would catch the missing where clause. Is it also possible you have a `TRUNCATE TABLE xxx` statement somewhere or someone maliciously affecting your database? – DavidG Oct 03 '14 at 08:37
  • @DavidG yes, such a trigger would help me identify the cause (malicious or otherwise). But how can I create such a trigger? – Salman A Oct 03 '14 at 09:31
  • Use the `SQL Server profiler` to log all queries which include the table name. – adrianm Oct 03 '14 at 09:36
  • 1
    If the table is being `TRUNCATE-`d then triggers won't be fired. – Martin Smith Oct 03 '14 at 11:38

2 Answers2

4

You can use Extended Events to monitor your system. Here a simple screen shot where are.

Extended Events

A simple policy can monitor for delete and truncate statements. When this events are raised details are written into file.

Here a screen with details (you can configure the script to collect more data) collected for delete statement.

List Events

Here the script used, modify the output file path

CREATE EVENT SESSION [CheckDelete] ON SERVER 
ADD EVENT sqlserver.sql_statement_completed(SET collect_statement=(1)
    ACTION(sqlserver.client_connection_id,sqlserver.client_hostname)
    WHERE ([sqlserver].[like_i_sql_unicode_string]([statement],N'%delete%') OR [sqlserver].[like_i_sql_unicode_string]([statement],N'%truncate%'))) 
ADD TARGET package0.event_file(SET filename=N'C:\temp\CheckDelete.xel',max_file_size=(50))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO
Max
  • 6,821
  • 3
  • 43
  • 59
0

This is a possibility that may help you. It creates a trigger on Table1 that sends an email when a process DELETEs more than 100 records. I'd modify the message to include some useful data like:

  1. Process ID (@@SPID)
  2. Host (HOST_NAME())
  3. Name of app (APP_NAME())
  4. And possibly the entire query

CREATE TRIGGER Table1MassDeleteTrigger
ON dbo.Activities
FOR DELETE 
AS
    DECLARE @DeleteCount INT = (SELECT COUNT(*) FROM deleted)

    IF(@DeleteCount > 100)
        EXEC msdb.dbo.sp_send_dbmail
        @profile_name = 'MailProfileName',
        @recipients = 'admin@yourcompany.com',
        @body = 'Something is deleting all your data!',
        @subject = 'Oops!';
DavidG
  • 113,891
  • 12
  • 217
  • 223