dutyDBA.com

Practical solutions from a real DBA

, ,

Using Extended Events, how to track who is using a table/view/stored procedure etc. in my SQL Server database?

Imagine this scenario: You are the DBA responsible for a large database that has hundreds of tables, stored procedures and views. Multiple different application teams and applications use this database. You think that there are many unused tables and stored procedures in this database, that can be dropped to clean up the database. You ask the application teams and users and they come up with a short list of tables, views and stored procedures that they think are no longer needed – but they are not 100% sure. Your job is to make sure none of those database objects are in use, before dropping them.

In other words, how to check if a table, view, stored procedure or any other database object is still being used? Sure, you can query the DMV sys.dm_db_index_usage_stats to check when a table or index is last used (seek/scan/lookup). I have a post about this here: How to check if an SQL Server database is in use? But, this only works for tables and indexes, and also, it cannot tell who (login/application name) is using that table.

In this case, how do you go about identifying who is using a database object? Most obvious option is to run SQL Server Profiler (or server side SQL trace) to trace all the SQL being run, and filter the text on your object name. This is very expensive in terms of CPU, and you cannot use this solution on busy production systems, especially if you want to run it for a longer period, like a week or two.

I am going to propose a solution for this requirement – as this article is a bit lengthy, I am dividing this into the following sub-sections:

Proposed solution

The solution? Extended Events or affectionately known as XEvents.

The idea? Every time an object like a table, view or stored procedure is used, SQL Server acquires a lock on that object (even if you use NOLOCK hint). As a minimum, SQL Server will acquire a Schema Stability (Sch-S) lock to protect the structure of an object while it is being used, ensuring that no DDL changes (ALTER, DROP, TRUNCATE, etc.) can occur at the same time. Getting the idea now? If we track the lock_acquired event on an object using Extended Events, the event will fire every time that object is used. And the good news – the event captures all sorts of information like the login name, application name, host name etc. This helps us identify who is using an object, so you can go speak to them before making any changes like dropping a table/stored proc etc.

I have implemented a little framework incorporating the above idea. This let’s you specify database objects from multiple databases to be tracked for lock_acquired event, for a specified number of days – and stores the trcking results into an output table for easy querying. Exclusions can be specified for applications like SQL Server Management Studio (SSMS), so that the exteneded events session is not capturing things like a manual query by a DBA in SSMS. The framework also makes sure the tracking stops at the specied end date, and takes care of purging the output data once the specified data reetntion date is reached.

List of tables and stored procedures required to deploy the solution

Let’s get to work! Before I show you the code, here’s a quick summary of all the objects that are part of this framework:

dbo.TrackedObjects

This table contains a list of database objects being tracked for their usage.
Each object is itendified uniquely by a combination of DatabaseID and ObjectID
dbo.ObjectTrackingResults

This table contains all the events captired by the Extended Events session.
Stores the event timestamp, client host name, login name, application name and the actual SQL command
This table could grow in size, if an active object is tracked over a longer perios.
Hence it is compressed by default (page compression – DATA_COMPRESSION=PAGE)
dbo.ApplicationExclusions

This table contains a row for each application name that needs to be excluded from tracking.
Limits the tracking to genuine application usage, rather than a DBA or developer manually querying/using an object.
By default it excludes events generated by SQL Server Management Studio (SSMS).
Conside adding SSMS addons like the Redgate SQL Prompt, to reduce noise from the output.
Simply add an application name to this table to exclude it from tracking.
dbo.TrackObjectUsage

Use this stored procedure to add a database object to the extended event session for tracking.
It takes two parameters:

@FullObjectName
Name of the database object to track. Must be in the format DatabaseName.SchemaName.ObjectName

@TrackingEndDate
The end date and time for tracking this object.
If not specified, the object will be tracked for 7 days.

Simply repeat the stored procedure call with a revised date, if you want to change the end date for tracking
dbo.SetupXESessionToTrackObjects

This is where all the magic happens. It takes 3 input parameters, all optional:

@XESessionName
Name of the extended events session. If not specified, defaults to XE_TrackObjectUsage

@XELPath
Folder path where the extended events output files are stored.
If not specified, defaults to the SQL Server error log folder.

@TrackingDataRetentionDays
Number of days to retain the extended events tracking output in the dbo.ObjectTrackingResults table.
If not specified, defaults to 30 days.

In short, this is how this stored procedure works:
– Check to see if there is already an existing Extended Events session running with the specifie name
– If it finds an existing session, with an output file, it processes the .XEL XML file
– Saves the output from the .XEL file into dbo.ObjectTrackingResults table
– After capturing the tracking data, it stops the extended events session, and deletes it
– Deletes the .XEL files that have already been processed
– It then recreates the extended events session by reading the latest list of objects from dbo.TrackedObjects
– It also incorporates application exclusions by reading the data from dbo.ApplicationExclusions
– Starts the extended events session with latest definition. Sets the session to auto start at server startup
– it then purges any expired object tracking requests from dbo.TrackedObjects
– Also purges any results from dbo.ObjectTrackingResults that are older than the default retention period

Code for creating the tables and stored procedures required to deploy the solution

Let’s look at the code for creating the tables and stored procedures now.

Please create all the following tables and stored procedures in your chosen database, typically a DBA Tools database:

dbo.TrackedObjects
IF OBJECT_ID('dbo.TrackedObjects', 'U') IS NOT NULL
BEGIN
	PRINT 'Table dbo.TrackedObjects already exists. Dropping it and recreating'
	DROP TABLE dbo.TrackedObjects
END
GO

CREATE TABLE dbo.TrackedObjects
(
	DatabaseID int NOT NULL,
	ObjectID int NOT NULL,
	DatabaseName sysname,
	ObjectName sysname,
	TrackingEndDate datetime
)
GO

IF OBJECT_ID('dbo.TrackedObjects', 'U') IS NOT NULL
BEGIN
	PRINT 'Table dbo.TrackedObjects has been created successfully'
	ALTER TABLE dbo.TrackedObjects ADD CONSTRAINT PK_TrackedObjects PRIMARY KEY NONCLUSTERED (DatabaseID, ObjectID) 
END
GO
dbo.ObjectTrackingResults
IF OBJECT_ID('dbo.ObjectTrackingResults', 'U') IS NOT NULL
BEGIN
	PRINT 'Table dbo.ObjectTrackingResults already exists. Dropping it and recreating'
	DROP TABLE dbo.ObjectTrackingResults
END
GO

CREATE TABLE dbo.ObjectTrackingResults
(
	EventTimeUTC datetime,
	LockType nvarchar(10),
	client_host_name sysname,
	client_app_name sysname,
	server_instance_name sysname,
	DBName sysname,
	ObjectID int,
	server_principal_name sysname,
	sql_text nvarchar(max),
	TrackedDatabaseName sysname,
	TrackedObjectName sysname
)
GO

IF OBJECT_ID('dbo.ObjectTrackingResults', 'U') IS NOT NULL
BEGIN
	PRINT 'Table dbo.ObjectTrackingResults has been created successfully'
	CREATE CLUSTERED INDEX C_TrackedObjects_TrackID_Covered ON dbo.ObjectTrackingResults(TrackedDatabaseName, TrackedObjectName, EventTimeUTC) WITH (DATA_COMPRESSION=PAGE)
END
GO						
dbo.ApplicationExclusions
IF OBJECT_ID('dbo.ApplicationExclusions', 'U') IS NOT NULL
BEGIN
	PRINT 'Table dbo.ApplicationExclusions already exists. Dropping it and recreating'
	DROP TABLE dbo.ApplicationExclusions
END
GO

CREATE TABLE dbo.ApplicationExclusions
(
	ApplicationName nvarchar(128) PRIMARY KEY CLUSTERED
)
GO

IF OBJECT_ID('dbo.ApplicationExclusions', 'U') IS NOT NULL
BEGIN
	PRINT 'Table dbo.ApplicationExclusions has been created successfully'

	INSERT INTO dbo.ApplicationExclusions (ApplicationName) VALUES
	('Microsoft SQL Server Management Studio'),
	('SQL Server Management Studio'),
	('Microsoft SQL Server Management Studio - Transact-SQL IntelliSense'),
	('Microsoft SQL Server Management Studio - Query')
END
GO
dbo.TrackObjectUsage
IF OBJECT_ID('dbo.TrackObjectUsage', 'P') IS NOT NULL
BEGIN
	PRINT 'Stored procedure dbo.TrackObjectUsage already exists. Dropping it and recreating'
	DROP PROC dbo.TrackObjectUsage
END
GO

CREATE PROC dbo.TrackObjectUsage
(
	@FullObjectName nvarchar(776),
	@TrackingEndDate datetime = NULL
)
AS
BEGIN

    -- Created by: Vyas Kondreddi
    -- https://dutydba.com
    
    SET NOCOUNT ON

    IF OBJECT_ID(@FullObjectName) IS NULL
    BEGIN
        RAISERROR('Specified object name ''%s'' not found', 11, 1, @FullObjectName)
        RETURN (-1)
    END

    IF PARSENAME(@FullObjectName, 1) IS NULL OR PARSENAME(@FullObjectName, 2) IS NULL OR PARSENAME(@FullObjectName, 3) IS NULL
    BEGIN
        RAISERROR('Object name ''%s'' is missing either database, owner or object name. Please provide full object name (DBName.SchemaName.ObjectName)', 11, 1, @FullObjectName)
        RETURN (-2)
    END

    IF (@TrackingEndDate IS NOT NULL) AND (@TrackingEndDate < CURRENT_TIMESTAMP)
    BEGIN
        RAISERROR('Specified tracking end date is in the past', 11, 1)
        RETURN (-3)
    END

    DECLARE @DBName sysname = PARSENAME(@FullObjectName, 3)
    DECLARE @ObjectName sysname = QUOTENAME(PARSENAME(@FullObjectName, 2)) + '.' + QUOTENAME(PARSENAME(@FullObjectName, 1))
    DECLARE @DBID int = DB_ID(@DBName)
    DECLARE @ObjectID int = OBJECT_ID(@FullObjectName)

    MERGE dbo.TrackedObjects AS tgt
    USING (SELECT @DBID, @ObjectID, @DBName, @ObjectName, @TrackingEndDate) AS src(DBID, ObjectID, DBName, ObjectName, TrackingEndDate)
    ON (tgt.DatabaseID = src.DBID AND tgt.ObjectID = src.ObjectID)
    WHEN MATCHED
        THEN
            UPDATE
            SET tgt.TrackingEndDate = COALESCE(src.TrackingEndDate, tgt.TrackingEndDate),
                tgt.DatabaseName = QUOTENAME(src.DBName),
                tgt.ObjectName = src.ObjectName
    WHEN NOT MATCHED
        THEN
            INSERT (DatabaseID, ObjectID, DatabaseName, ObjectName, TrackingEndDate)
            VALUES (@DBID, @ObjectID, QUOTENAME(@DBName), @ObjectName, COALESCE(@TrackingEndDate, DATEADD(dd, 7, CURRENT_TIMESTAMP)))
    OUTPUT inserted.*;
END
GO

IF OBJECT_ID('dbo.TrackObjectUsage', 'P') IS NOT NULL
BEGIN
	PRINT 'Stored proc dbo.TrackObjectUsage has been created successfully'
END
GO
dbo.SetupXESessionToTrackObjects
IF OBJECT_ID('dbo.SetupXESessionToTrackObjects', 'P') IS NOT NULL
BEGIN
	PRINT 'Stored procedure dbo.SetupXESessionToTrackObjects already exists. Dropping it and recreating'
	DROP PROC dbo.SetupXESessionToTrackObjects
END
GO

CREATE PROC dbo.SetupXESessionToTrackObjects
(
  @XESessionName sysname = 'XE_TrackObjectUsage',
	@XELPath nvarchar(1024) = NULL,
	@TrackingDataRetentionDays int = 30
)
AS
BEGIN

    -- Created by: Vyas Kondreddi
    -- https://dutydba.com
    
    SET NOCOUNT ON

	DECLARE @XELFileName nvarchar(512), @XECMD nvarchar(4000), @RetVal int, @RowCTR int, @FilterClause nvarchar(4000) = '',
	@XELFileNameWild nvarchar(512)

	IF EXISTS (SELECT * FROM sys.server_event_sessions WHERE name = @XESessionName)
	BEGIN --START:Session definition exists
		RAISERROR('Extended events session %s exists. Processing it', 0, 1, @XESessionName)
		
		SET @XELFileName = 
		(
			SELECT
				CAST(esf.value AS nvarchar(512))
			FROM
				sys.server_event_sessions  AS es 
				JOIN 
				sys.server_event_session_fields AS esf 
				ON es.event_session_id = esf.event_session_id
				AND esf.name = 'filename'
			WHERE
				es.name = @XESessionName
		)

		IF @XELFileName IS NULL
		BEGIN --START:Session found with no target file
			RAISERROR('No target file found for session %s', 0, 1, @XESessionName)
		END --END:Session found with no target file
		ELSE
		BEGIN --START:Session found with target file
			RAISERROR('Target file found for session %s: %s', 0, 1, @XESessionName, @XELFileName)
			SET @XELFileNameWild = REPLACE(@XELFileName, '.xel', '*.xel')

			INSERT INTO dbo.ObjectTrackingResults
			(
				EventTimeUTC,
				LockType,
				client_host_name,
				client_app_name,
				server_instance_name,
				DBName,
				ObjectID,
				server_principal_name,
				sql_text,
				TrackedDatabaseName,
				TrackedObjectName
			)
			SELECT
				event_xml.value('(/event/action[@name="collect_system_time"]/value)[1]', 'datetime') AS EventTimeUTC,
				event_xml.value('(/event/data[@name="mode"]/text)[1]', 'varchar(25)') AS LockType,
				event_xml.value('(/event/action[@name="client_hostname"]/value)[1]', 'sysname') AS client_host_name,
				event_xml.value('(/event/action[@name="client_app_name"]/value)[1]', 'sysname') AS client_app_name,
				event_xml.value('(/event/action[@name="server_instance_name"]/value)[1]', 'sysname') AS server_instance_name,
				event_xml.value('(/event/action[@name="database_name"]/value)[1]', 'sysname') AS DBName,
				event_xml.value('(/event/data[@name="object_id"]/value)[1]', 'int') AS ObjectID,
				event_xml.value('(/event/action[@name="server_principal_name"]/value)[1]', 'sysname') AS server_principal_name,
				event_xml.value('(/event/action[@name="sql_text"]/value)[1]', 'nvarchar(max)') AS sql_text,
				tobj.DatabaseName AS TrackedDatabaseName,
				tobj.ObjectName AS TrackedObjectName
			FROM
				sys.fn_xe_file_target_read_file(@XELFileNameWild, NULL, NULL, NULL) AS F
				CROSS APPLY 
				(SELECT CAST(F.event_data AS xml)) AS X(event_xml)
				LEFT JOIN
				dbo.TrackedObjects AS tobj
				ON
					tobj.DatabaseID = event_xml.value('(/event/data[@name="database_id"]/value)[1]', 'int')
					AND tobj.ObjectID = event_xml.value('(/event/data[@name="object_id"]/value)[1]', 'int')
			SET @RowCTR = @@ROWCOUNT
			RAISERROR('%d results retreived from XE sesssion %s into dbo.ObjectTrackingResults', 0, 1, @RowCTR, @XESessionName)

			IF EXISTS(SELECT 1 FROM sys.dm_xe_sessions WHERE name = @XESessionName)
			BEGIN --START: Session currently running
				--Stop the session
				RAISERROR('Stopping the currently running session %s', 0, 1, @XESessionName)
				SET @XECMD = 'ALTER EVENT SESSION ' + QUOTENAME(@XESessionName) + ' ON SERVER STATE = STOP'
				EXEC sp_executesql @XECMD
			END --END: Session currently running
			ELSE
			BEGIN
				RAISERROR('Session %s currently not running', 0, 1, @XESessionName)
			END
			--Delete the files
			SET @XECMD = 'del ' + QUOTENAME(@XELFileNameWild, '"')
			RAISERROR('Deleting session output files: %s', 0, 1, @XECMD)
			EXEC @RetVal = xp_cmdshell @XECMD, NO_OUTPUT
			IF @RetVal = 1 RAISERROR('Error occured while deleting session output files: %s. Clean up manually', 0, 1, @XECMD)

		END --END:Session found with target file

		RAISERROR('Dropping extended events session: %s', 0, 1, @XESessionName)
		SET @XECMD = 'DROP EVENT SESSION ' + @XESessionName + ' ON SERVER'
		EXEC sp_executesql @XECMD
	END --END:Session definition exists
	ELSE
	BEGIN
		RAISERROR('Session definition not found for: %s', 0, 1, @XESessionName)
	END

	--Delete any tracking requests that are in the past
	DELETE dbo.TrackedObjects WHERE TrackingEndDate < CURRENT_TIMESTAMP
	SET @RowCTR = @@ROWCOUNT
	RAISERROR('%d expired tracking requests have been deleted', 0, 1, @RowCTR)

	--Delte results for expired tracking requests, that are older than retention period.
	DELETE dbo.ObjectTrackingResults
	FROM dbo.ObjectTrackingResults AS otr
	WHERE otr.EventTimeUTC < DATEADD(dd, -@TrackingDataRetentionDays, GETUTCDATE())
	AND NOT EXISTS
	(
		SELECT 1 FROM dbo.TrackedObjects AS tobj 
		WHERE	tobj.DatabaseName = otr.TrackedDatabaseName
		AND		tobj.ObjectName = otr.TrackedObjectName
	)
	SET @RowCTR = @@ROWCOUNT
	RAISERROR('%d result rows deleted for expired tracking requests', 0, 1, @RowCTR)

	DECLARE @FilterDBID int = 0, @FilterObjectID int = 0
	SET @FilterClause = '
			(
	' 
	SET @FilterClause += '			[sqlserver].[is_system]=(0)'
	SET @FilterClause += '
			)'
	IF EXISTS (SELECT 1 FROM dbo.TrackedObjects) SET @FilterClause += '
			AND 
		'
	IF EXISTS (SELECT 1 FROM dbo.TrackedObjects)
	BEGIN
		DECLARE @ObjectFilters nvarchar(4000) = ''
		SELECT @ObjectFilters = @ObjectFilters + 
		'
				([database_id]=(' + CAST(DatabaseID AS varchar(12)) + ') AND [object_id]=(' + CAST(ObjectID AS varchar(12)) + ')) OR '
		FROM dbo.TrackedObjects
		SET @ObjectFilters = LEFT(@ObjectFilters, LEN(@ObjectFilters)-4)
		SET @ObjectFilters = '	(' + @ObjectFilters + ')
				'
	END
	ELSE
	BEGIN
		RAISERROR('NO TRACKED OBJECTS FOUND', 0, 1)
		RAISERROR('NOT CREATING the extended events session: %s', 0, 1, @XESessionName)
		RETURN (-1)
	END

	IF EXISTS (SELECT 1 FROM dbo.ApplicationExclusions) SET @ObjectFilters += '
			)
			AND 
	'
	IF EXISTS (SELECT 1 FROM dbo.ApplicationExclusions)
	BEGIN
		DECLARE @AppExclusions nvarchar(4000) = ''
		SELECT @AppExclusions = @AppExclusions + 
		'
				[sqlserver].[client_app_name]<>N''' + ApplicationName + ''' AND '
		FROM dbo.ApplicationExclusions
		SET @AppExclusions = LEFT(@AppExclusions, LEN(@AppExclusions)-4)
		SET @AppExclusions = '		(' + @AppExclusions + '
			)
				'
	END
	ELSE
	BEGIN
		SET @AppExclusions = ')'
	END
	SET @XELPath = LTRIM(RTRIM(@XELPath))
	IF RIGHT(@XELPath, 1) <> '\' SET @XELPath += '\'
	SET @XELFileName = COALESCE(
	@XELFileName, 
	COALESCE(@XELPath, REPLACE(CAST(SERVERPROPERTY('ErrorLogFileName') AS nvarchar(512)), '\ERRORLOG', '') + '\') + @XESessionName + '.XEL'
	)
	

	SET @XECMD = '
	CREATE EVENT SESSION ' + QUOTENAME(@XESessionName) + ' ON SERVER 
	ADD EVENT sqlserver.lock_acquired
	(
		ACTION
		(
			package0.collect_system_time,
			sqlserver.client_app_name,
			sqlserver.client_hostname,
			sqlserver.database_name,
			sqlserver.server_instance_name,
			sqlserver.server_principal_name,
			sqlserver.sql_text
		)
		WHERE 
		(' +
		@FilterClause + @ObjectFilters + @AppExclusions
		+ '
		)
	)
	ADD TARGET package0.event_file(SET filename=N''' + COALESCE(@XELFileName, '') + ''',max_file_size=(100))
	WITH (MAX_MEMORY=65536 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=ON)'
	
	RAISERROR('Re/Creating extended events session: %s', 0, 1, @XESessionName)
	RAISERROR('%s', 0, 1, @XECMD)
	EXEC sp_executesql @XECMD
	RAISERROR('Startting extended events session: %s', 0, 1, @XESessionName)
	SET @XECMD = 'ALTER EVENT SESSION ' + QUOTENAME(@XESessionName) + ' ON SERVER STATE = START'
	EXEC sp_executesql @XECMD
END
GO

IF OBJECT_ID('dbo.SetupXESessionToTrackObjects', 'P') IS NOT NULL
BEGIN
	PRINT 'Stored proc dbo.SetupXESessionToTrackObjects has been created successfully'
END
GO

How to configure and use the solution?

Step 1: Deploy code

Deploy all the tables and stored procedures required by this framework by running the code presented above. Ideally you would deploy this code into one of your tools/utilities database use by your DBA team. Simply copy the code into your SSMS query window and execute, to create the objects.

Step 2: Start tracking the objects

Once you have identified which table/view/stored procedure or function to track, call the stored procedure dbo.TrackObjectUsage for each of the objects as shown below. Make sure you specify the full object name in the format DatabaseName.SchemaName.ObjectName. The tracking end date should be a future date. You should get a resultset back showing your object has been successfully add to the table dbo.TrackedObjects.

If you want to revise the tracking end date, simply rerun the stored procedure with the revised date.

Note: The extended events session will not be created if no objects are added for tracking.

SQL
EXEC dbo.TrackObjectUsage 
	@FullObjectName = 'MyFlights.dbo.Airports', 
	@TrackingEndDate = '20260710 17:00'

EXEC dbo.TrackObjectUsage 
	@FullObjectName = 'MyFlights.dbo.Trips', 
	@TrackingEndDate = '20260710 17:00'

Step 3: Add any application names to exclude (Optional)

By default, the code excludes any events triggered by SQL Server Management Studio (SSMS). If you want to add any additional application exclusions, simply add a row into the dbo.ApplicationExclusions table. Consider excluding SQLCMD, ISQL, OSQL etc if appropriate for your requirement. If you do not want to filter our SSMS events, simply delete the entries from dbo.ApplicationExclusions table.

Here’s an example to add an exclusion for Redgate SQL Prompt:

SQL
INSERT INTO dbo.ApplicationExclusions (ApplicationName) VALUES ('Redgate SQL Prompt')

Step 4: Set up the Extended Events session

Run the stored procedure dbo.SetupXESessionToTrackObjects to create the extended events session. It will only create the session, if at least one entry exists in the dbo.TrackedObjects table.

If you do not specify @XELPath parameter, the .XEL output files will be created in the default error log folder.

If @TrackingDataRetentionDays is not specified, the tracking output data will be retained for 30 days.

SQL
EXEC dbo.SetupXESessionToTrackObjects 
	@XESessionName = 'XE_TrackObjectUsage',
	@XELPath = 'C:\SQLServer\SQL2025\MSSQL17.SQL2025\MSSQL\Log\ERRORLOG', --OPTIONAL
	@TrackingDataRetentionDays = 60 --OPTIONAL

Now that the extended events session is up and running, sit back and wait for a user or application to use the object that you are tracking.

Step 5: Schedule the stored procedure dbo.SetupXESessionToTrackObjects as a job (IMPORTANT)

Create an SQL Agent job that runs every 4 hours (or any other frequency of your choice), to run the stored procedure dbo.SetupXESessionToTrackObjects. Only when you run this stored procedure, the data collected by the extende events session gets processed into the dbo.ObjectTrackingResults table. This is when any new object tracking requests get picked up as well.

IMPORTANT NOTE: To get the captured results processed into the table dbo.ObjectTrackingResults, OR to get new object tracking requests from dbo.TrackedObjects to be picked up, you must execute the stored procedure dbo.SetupXESessionToTrackObjects.

My recommendation is to schedule the stored procedure dbo.SetupXESessionToTrackObjects as an SQL Agent job, to run every 4 hours or similar.

If you would like to see tracking results as quickly as possible, you could even schedule your job to run once every hour or sooner.

Step 6: Checking the results

Query the dbo.ObjectTrackingResults table to see the information captured by the extended events session.

SQL
SELECT *
FROM dbo.ObjectTrackingResults
ORDER BY EventTimeUTC

Provided there has been some activity on the tracked objects, you would get output similar to below screenshot:

The data from the above screenshot clearly shows you which users or applications are still accessing your tables/views/stored procedures etc. You can use this information to reach out to the relevent users or developers before making any changes to these objects.

Summary and additional Notes

I hope the detailed explanation has been clear, and that you are comfortable in setting this up in your environment. I run this on all my SQL Serevrs to be able to easily track who is using the objects I am interested in. The most common use case is that, a developer wants to make changes to a table that could break an application. They already have a list of applications that would be impacted. But they are worried that there may be other apps or processes that they are not aware of. That is when this process comes in handy. I simply set up tracking on that table, let it run for a month or so and then review the results with the developer.

I hope this page also serves you as a good example of how to set up and manage extended events sessions. It shows you how to check if an extended events session exists, how to process the XML data from the .XEL files using XQuery language and syntax, how to stop and start extended event sessions programmatically, how to delete the sessions etc.

Additionally it also shows you how to use the MERGE statement (inside dbo.TrackObjectUsage)

Enjoy and please do leave a comment to share your thoughts!

See also: How to check if an SQL Server database is in use?

Leave a Reply

Your email address will not be published. Required fields are marked *