I used to run a series on Hero’s and Sherlock Holmes is one of my favorite. There is always a need to get to the bottom of the problem statement and whether you are a developer or a DBA, at least once you might have been asked one of the following “Who” question after a disaster.
- Who dropped table in the database? From which application? When?
- Who dropped database? What was the date and time?
- Who created database on production server?
- Who altered the database?
- Who dropped the schema?
- Who altered the schema?
And there are many other similar questions. Generally rich companies have auditing enabled and they have many tools which might be capturing all DDLs via either Auditing or via 3rd party tools. Many of DBAs and developer don’t know that there is a default trace which runs in the background in every SQL Server installation
Here are few usage of default traces which are via SSMS.
SQL SERVER – SSMS: Configuration Changes History
SQL SERVER – SSMS: Schema Change History Report
Let’s look at the events captured by the default trace.
SELECT DISTINCT Trace.EventID, TraceEvents.NAME AS Event_Desc
FROM ::fn_trace_geteventinfo(1) Trace
,sys.trace_events TraceEvents
WHERE Trace.eventID = TraceEvents.trace_event_id
Here is what we would get in SQL Server 2014
Event_ID | Event_Desc |
18 | Audit Server Starts And Stops |
20 | Audit Login Failed |
22 | ErrorLog |
46 | Object:Created |
47 | Object:Deleted |
55 | Hash Warning |
69 | Sort Warnings |
79 | Missing Column Statistics |
80 | Missing Join Predicate |
81 | Server Memory Change |
92 | Data File Auto Grow |
93 | Log File Auto Grow |
94 | Data File Auto Shrink |
95 | Log File Auto Shrink |
102 | Audit Database Scope GDR Event |
103 | Audit Schema Object GDR Event |
104 | Audit Addlogin Event |
105 | Audit Login GDR Event |
106 | Audit Login Change Property Event |
108 | Audit Add Login to Server Role Event |
109 | Audit Add DB User Event |
110 | Audit Add Member to DB Role Event |
111 | Audit Add Role Event |
115 | Audit Backup/Restore Event |
116 | Audit DBCC Event |
117 | Audit Change Audit Event |
152 | Audit Change Database Owner |
153 | Audit Schema Object Take Ownership Event |
155 | FT:Crawl Started |
156 | FT:Crawl Stopped |
164 | Object:Altered |
167 | Database Mirroring State Change |
175 | Audit Server Alter Trace Event |
218 | Plan Guide Unsuccessful |
As we can see there are various interesting events. Object:Altered, Object:Created and Object:Deleted can help us in identifying who dropped, altered or created any object. Once we get event class ID for the event of interest, we can use below query and replace the Event class ID.
-- read all available traces.
DECLARE @current VARCHAR(500);
DECLARE @start VARCHAR(500);
DECLARE @indx INT;
SELECT @current = path
FROM sys.traces
WHERE is_default = 1;
SET @current = REVERSE(@current)
SELECT @indx = PATINDEX('%\%', @current)
SET @current = REVERSE(@current)
SET @start = LEFT(@current, LEN(@current) - @indx) + '\log.trc';
-- CHNAGE FILER AS NEEDED
SELECT *
FROM::fn_trace_gettable(@start, DEFAULT)
WHERE EventClass IN (92,93) -- growth event
ORDER BY StartTime DESC
In above, I have used EventClass 92 and 93 to track database auto-growth events. Here is the query to find who dropped / created or altered object in database or database itself.
-- read all available traces.
DECLARE @current VARCHAR(500);
DECLARE @start VARCHAR(500);
DECLARE @indx INT;
SELECT @current = path
FROM sys.traces
WHERE is_default = 1;
SET @current = REVERSE(@current)
SELECT @indx = PATINDEX('%\%', @current)
SET @current = REVERSE(@current)
SET @start = LEFT(@current, LEN(@current) - @indx) + '\log.trc';
-- CHNAGE FILER AS NEEDED
SELECT CASE EventClass
WHEN 46 THEN 'Object:Created'
WHEN 47 THEN 'Object:Deleted'
WHEN 164 THEN 'Object:Altered'
END, DatabaseName, ObjectName, HostName, ApplicationName, LoginName, StartTime
FROM::fn_trace_gettable(@start, DEFAULT)
WHERE EventClass IN (46,47,164) AND EventSubclass = 0 AND DatabaseID <> 2
ORDER BY StartTime DESC
Have you ever heard of someone being fired based on such auditing?
Reference: Pinal Dave (https://blog.sqlauthority.com)
14 Comments. Leave new
Hello Pinal!
Small typo in the default trace query “SELECT DISTINCT Trace.Event_ID, TraceEvents.NAME AS Event_Desc…”.
Instead of Trace.Event_ID the correct column is Trace.EventID.
Greetings,
Michael
Thanks, you are correct. I fixed the issue.
Hello Pinal,
I am preparing for SQL certification 70-461. Kindly help me know how to clear the exam in one go?
Sonali
There are self study material.
This is helpful if your trace file has rolled and you can no longer query it:
https://www.sqlskills.com/blogs/paul/using-fn_dblog-fn_dump_dblog-and-restoring-with-stopbeforemark-to-an-lsn/
Very true – Paul is the final authority when it is about SQL.
I like how you discretely added the part at the end about people potentially losing jobs – while dropping a production DB should only ever be done with an RFC/CRF, or at least written confirmation from line management, it’s also important to consider that someone made an honest mistake – not we just DBA/Dev’s who have SA rights in some environments – an honest man whose livelihood you may endanger. Although we are sometimes entrusted with very sensitive data, day-to-day it’s rare that DBA’s must deal with ethical issues, but this is definitely an ethical consideration.
Hi Pinal,
Is there anyway we can capture information into table when database drop command executed and who dropped it.
Thanks
Sankar
This has been awesome help for me!! Can you please tell me if we can get the MAC ID of the PC/LAPTOP since we are able to get the hostname.
not possible from SQL side.
** When the records got deleted from the tables?
** What was the account used ?
Is there any query for how to find when and whom deleted table records
Hi Pinal,
Great…It’s very helped for me
Thanks,
Venkat
REALLY, THANK YOU
I VERY GRATEFUL