![]() |
|
|
By: Arshad Ali | Read Comments (6) | Print Arshad is a SQL and BI Developer focusing on Data Warehousing projects for Microsoft. Related Tips: More |
|
As a DBA, we often need a way to track what events are occurring (changes that are being made) on SQL Server or at the database level. So what is a way to track these changes without much impact on SQL Server performance?
SQL Server 2005 and onwards provides event notifications mechanism for tracking all events or changes happening at the database or instance level. This can be done with DDL triggers or SQL traces, but event notifications have the advantage of being asynchronous in nature and running outside of the scope of the transaction and hence it can run inside (or be a part of) a database application to capture defined events without using the resources allocated to the transaction.
Event notification is a programmatic alternative to using DDL triggers or SQL traces and executes in the response to different DDL statements, SQL traces, Service Broker events (like QUEUE_ACTIVATION or BROKER_QUEUE_DISABLED) and then sends this information, in XML format, to the SQL Server Service Broker (SSB) service. In other words, when you create a notification, SQL Server tracks the defined events and the occurrence of that event is written to the SSB service and then you can retrieve this information asynchronously from the SSB queue when needed. Discussion of Service Broker is out of the scope of this tip, but you can learn more about SQL Server Service Broker here.
In Script #1, I am first checking if Service Broker is enabled at the database level and if not then I am enabling it. Next I am creating a SSB queue and the SSB service will use this queue to store messages coming to this service. This service uses the built-in contract (a contract defines a type of message that can be sent to the SSB service), http://schemas.microsoft.com/SQL/Notifications/PostEventNotification, which is specifically for event notification. Note: you will need exclusive access to the database to run the alter database command.
| Script #1 - Setting up environment for demonstration |
|---|
|
--Check if the database is enabled for Service Broker --If not then enable it IF EXISTS (SELECT * FROM sys.databases WHERE name = 'AdventureWorks' AND is_broker_enabled = 0) ALTER DATABASE AdventureWorks SET ENABLE_BROKER; GO USE AdventureWorks GO --Create a queue which will hold the tracked information CREATE QUEUE dbo.EventNotificationQueue GO --Check if the queue is created or not SELECT * FROM sys.service_queues WHERE name = 'EventNotificationQueue' GO --Create a service on which tracked information will be sent CREATE SERVICE [//AdventureWorks/EventNotificationService] ON QUEUE dbo.EventNotificationQueue ([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification]) GO --Check if the service is created or not SELECT * FROM sys.services WHERE name = '//AdventureWorks/EventNotificationService' GO |
In Script #2, I am creating two database level notifications. The first will notify when there is a create table command execution and the second will notify when there is an alter table command execution. You can also create a notification event group; for example you can create a single notification with DDL_TABLE_EVENTS to track all events of a table like creation, alteration and drop.
| Script #2 - Creating database level notification |
|---|
|
--Create a notification to track create table command CREATE EVENT NOTIFICATION NotifyCREATETABLEEvents ON DATABASE FOR CREATE_TABLE TO SERVICE '//AdventureWorks/EventNotificationService' , 'current database' GO --Create a notification to track alter table command CREATE EVENT NOTIFICATION NotifyALTERTABLEEvents ON DATABASE FOR ALTER_TABLE TO SERVICE '//AdventureWorks/EventNotificationService' , 'current database' GO --Check if both the above notifications created or not SELECT * FROM sys.event_notifications WHERE name IN ('NotifyCREATETABLEEvents','NotifyALTERTABLEEvents') GO |
In Script #3, I am creating a server level notification that will be raised whenever an error is raised at the SQL Server instance level. You can query the sys.server_event_notifications catalog view to check if a notification exists on the server or not.
| Script #3 - Creating server level notification |
|---|
|
--Create a notification to error occuring at server level CREATE EVENT NOTIFICATION NotifyERROREvents ON SERVER WITH FAN_IN FOR ERRORLOG TO SERVICE '//AdventureWorks/EventNotificationService', 'current database' GO --Check if the above notification was created or not SELECT * FROM sys.server_event_notifications WHERE name IN ('NotifyERROREvents') GO |
In Script #4, let's verify if these event notifications are actually working. In this script, I am creating a table, then altering it, which will be tracked by both the database level event notifications we created above and then I am using RAISERROR (WITH LOG clause is required to be tracked by server level event notification) to generate an error in SQL Server which will be tracked by our last server level event notification.
| Script #4 - Generating database and server level events |
|---|
|
--Generate a create table event CREATE TABLE ABC ( COL1 INT, COL2 INT ) GO --Generate an alter table event ALTER TABLE ABC ADD COL3 INT GO --Generate a server level event RAISERROR (N'Generating error for Event Notification testing...', 16, 1) WITH LOG GO --Review if the events were tracked in queue SELECT CAST(message_body AS XML) AS message_in_xml FROM dbo.EventNotificationQueue GO |
In Script #5, event notifications send tracked information to the SSB service in XML format; you can query the queue to see the tracked information, but you need to use the RECEIVE command to retrieve messages from the queue, process them and remove them from the queue as shown below. With the RECEIVE command you can specify the number of records you want to retrieve at one time. In this script, I am using a TOP(1) command to retrieve the top 1 record form the queue and displaying the information that it contains. Event notification sends information in XML format (remember we used the built-in contract with the service we created that defines that only XML data can be written to the service) and that's the reason I am casting the message body to an XML data type. Since I am using a TOP(1) clause with the RECEIVE command, I ran the below command 3 times, since there were 3 records in the queue. You can see the result in the image below the query. You can also use a looping construct to read all the records from the queue instead of running the same script multiple times.
| Script #5 - Retrieving records from the queue |
|---|
|
DECLARE @TargetDialogHandle UNIQUEIDENTIFIER; DECLARE @EventMessage XML; DECLARE @EventMessageTypeName sysname; WAITFOR ( RECEIVE TOP(1) @TargetDialogHandle = conversation_handle, @EventMessage = CONVERT(XML, message_body), @EventMessageTypeName = message_type_name FROM dbo.EventNotificationQueue ), TIMEOUT 1000; SELECT @TargetDialogHandle AS DialogHandle, @EventMessageTypeName AS MessageTypeName, @EventMessage.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(128)' ) as EventType, @EventMessage.value('(/EVENT_INSTANCE/ServerName)[1]', 'varchar(128)' ) as ServerName, @EventMessage.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(128)' ) as DatabaseName, @EventMessage.value('(/EVENT_INSTANCE/LoginName)[1]', 'varchar(128)' ) as LoginName, @EventMessage.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)') AS TSQLCommand, @EventMessage.value('(/EVENT_INSTANCE/TextData)[1]', 'varchar(128)' ) AS TextData, @EventMessage.value('(/EVENT_INSTANCE/Severity)[1]', 'varchar(128)' ) AS Severity, @EventMessage.value('(/EVENT_INSTANCE/Error)[1]', 'varchar(128)' ) AS ErrorNumber |

In Script #6, you can use this code to cleanup and drop all the objects, in the reverse order of their creation, which we created for this demonstration.
| Script #6 - Cleaning up the objects created |
|---|
|
DROP EVENT NOTIFICATION NotifyCREATETABLEEvents ON DATABASE GO DROP EVENT NOTIFICATION NotifyALTERTABLEEvents ON DATABASE GO DROP EVENT NOTIFICATION NotifyERROREvents ON SERVER GO DROP TABLE ABC GO DROP SERVICE [//AdventureWorks/EventNotificationService] GO DROP QUEUE dbo.EventNotificationQueue GO |
| Share: | Share | Tweet |
|
![]() |
![]() |
Free SQL Server Learning |
| Monday, September 27, 2010 - 9:35:59 AM - Ranga | Read The Tip |
|
Good article, very simple and precise. |
|
| Friday, October 08, 2010 - 6:12:44 PM - Amin Mesbahi | Read The Tip |
|
Thanks for your article but SSNS (SQL Server Notification Services) is a discontinued feature since SQL Server 2008... This feature is useful only in SQL Server 2005 not lower versions not highr versions! |
|
| Saturday, October 09, 2010 - 2:42:06 AM - Arshad | Read The Tip |
|
Hi Amin, Event notification is a feature based on SQL Server Service Broker and available even in SQL Server 2008 and SQL Server 2008 R2 as well. Hope it helps. Please let me know if you have any doubts. |
|
| Wednesday, October 20, 2010 - 1:40:24 PM - Manoj | Read The Tip |
|
I am trying to implement a feature in SQL Server so that when a new login is created in SQL Server 2005, it should raise an event so that the client application can add the newly created login info to another custom table. I recently read about deprecation of SQL Server Notification Services in SQL Server 2008. Although I am not very sure that if that was the right solution for this problem. Does anyone know what would be a correct solution for such a problem? Which feature to use to send a notification to another program that a new login has been created in SQL Server 2005. |
|
| Monday, January 09, 2012 - 10:47:27 PM - Aaron Bertrand | Read The Tip |
|
I know it's been 13 months but I just wanted to mention that event notifications and notification services are two very different concepts. While the latter is deprecated the former is certainly not. |
|
| Tuesday, January 10, 2012 - 5:28:18 AM - Arshad | Read The Tip |
|
Yes you are absolutely right Aaron, You might also like to have look on extended events features of SQL Server 2008 and later versions which provide more granular level control on tracing : http://www.mssqltips.com/sqlservertip/2144/an-overview-of-extended-events-in-sql-server-2008/ |
|
|
privacy | disclaimer | copyright | advertise | about authors | contribute | feedback | giveaways | user groups Some names and products listed are the registered trademarks of their respective owners. Edgewood Solutions LLC | MSSharePointTips.com | MSSQLTips.com |