Who is changing your objects (tables, views, stored procedures, functions etc) or creating new one, or who actually deleted one or more objects? These are normal questions when more than one person are working on a same database. Production environment is mostly kept secure for unauthorized access and few known persons are allowed to make changes BUT still you need to keep a track of these changes and if it’s a development database then it is also must to keep a complete log of each change. There are tree major ways in which we can keep track of these changes.
- DDL Trigger and Event Notifications
- Extended Events
- Service Broker and Event Notifications
The DDL Trigger method is most commonly used method, where we write a
DLL (after) trigger on each database separately and using information from event notifications, we decide whether to rollback any DDL change or just dump change information to a table.
How to create a DDL Trigger?
Extended Events, is the most advance method, not only for DDL change tracking but it’s going to be next biggest
tool for DBAs. SQL Server 2012, introduced three new events for DDL change tracking.
- object_altered
- object_created
- object_deleted
Paul Randal script for extended event creation is good one to follow, but don’t forget to change events.
Service Broker (with event notifications), is the best way I have ever found for DDL Change Tracking before SQL Server 2012. Though its initial steps are bit lengthy, that is why; most people avoid using this method.
Using service broker, you can dump all databases changes data to a single table on an instance, or you can transmit changes information as a message to other instance on internet (if need to create a single point of administration for multiple instances).
(What is Service Broker and what type of objects you need to create, can be found
here and
here).
Use following simple steps to create DDL Changes Log, for multiple databases on an instance.
IF NOT EXISTS (SELECT 1 FROM sys.databases WHERE name = 'ConnectDBA')
CREATE DATABASE ConnectDBA
GO
USE [ConnectDBA]
GO
CREATE TABLE [dbo].DDLChangeLog(
[EventType] [varchar](250) NULL,
[PostTime] [datetime] NULL,
[ServerName] [varchar](250) NULL,
[LoginName] [varchar](250) NULL,
[UserName] [varchar](250) NULL,
[DatabaseName] [varchar](250) NULL,
[SchemaName] [varchar](250) NULL,
[ObjectName] [varchar](250) NULL,
[ObjectType] [varchar](250) NULL,
[TSQLCommand] [varchar](max) NULL
) ON [PRIMARY]
GO
IF EXISTS ( SELECT *
FROM sys.databases
WHERE name = 'ConnectDBA'
AND is_broker_enabled = 0 )
ALTER DATABASE ConnectDBA SET ENABLE_BROKER ;
GO
CREATE PROCEDURE [ConnectDBA_Queue_EventNotificatier]
WITH EXECUTE AS OWNER
AS
DECLARE @message_body XML
WHILE ( 1 = 1 )
BEGIN
BEGIN TRANSACTION
WAITFOR ( RECEIVE TOP ( 1 )
@message_body = CONVERT(XML, CONVERT(NVARCHAR(MAX), message_body))
FROM dbo.[ConnectDBA_EventNotificationQueue] ), TIMEOUT 1000
IF ( @@ROWCOUNT = 0 )
BEGIN
ROLLBACK TRANSACTION
BREAK
END
INSERT INTO DDLChangeLog
SELECT @message_body.value('(/EVENT_INSTANCE/EventType)[1]',
'varchar(128)') AS EventType,
CONVERT(DATETIME, @message_body.value('(/EVENT_INSTANCE/PostTime)[1]', 'varchar(128)'))
AS PostTime,
@message_body.value('(/EVENT_INSTANCE/ServerName)[1]',
'varchar(128)') AS ServerName,
@message_body.value('(/EVENT_INSTANCE/LoginName)[1]',
'varchar(128)') AS LoginName,
@message_body.value('(/EVENT_INSTANCE/UserName)[1]',
'varchar(128)') AS UserName,
@message_body.value('(/EVENT_INSTANCE/DatabaseName)[1]',
'varchar(128)') AS DatabaseName,
@message_body.value('(/EVENT_INSTANCE/SchemaName)[1]',
'varchar(128)') AS SchemaName,
@message_body.value('(/EVENT_INSTANCE/ObjectName)[1]',
'varchar(128)') AS ObjectName,
@message_body.value('(/EVENT_INSTANCE/ObjectType)[1]',
'varchar(128)') AS ObjectType,
@message_body.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]',
'nvarchar(max)') AS TSQLCommand
COMMIT TRANSACTION
END
GO
CREATE QUEUE [ConnectDBA_EventNotificationQueue]
WITH ACTIVATION
( STATUS= ON, PROCEDURE_NAME = DBO.[ConnectDBA_Queue_EventNotificatier],
MAX_QUEUE_READERS = 2,
EXECUTE AS OWNER)
GO
CREATE SERVICE [ConnectDBA_EventNotificationService]
AUTHORIZATION dbo ON QUEUE dbo.ConnectDBA_EventNotificationQueue
([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification])
GO
IF EXISTS ( SELECT *
FROM sys.databases
WHERE name = 'NotifierChekcerDB'
AND is_broker_enabled = 0 )
ALTER DATABASE YourDBNameHere SET ENABLE_BROKER ;
GO
USE YourDBNameHere
GO
CREATE EVENT NOTIFICATION [ConnectDBA_NotifierFor_DDL_DATABASE_LEVEL_EVENTS] ON
DATABASE FOR
CREATE_TABLE,ALTER_TABLE,DROP_TABLE,CREATE_VIEW,ALTER_VIEW,DROP_VIEW,CREATE_INDEX,
ALTER_INDEX,DROP_INDEX,CREATE_FUNCTION,ALTER_FUNCTION,DROP_FUNCTION,CREATE_PROCEDURE,
ALTER_PROCEDURE,DROP_PROCEDURE,CREATE_TRIGGER,ALTER_TRIGGER,DROP_TRIGGER,CREATE_SCHEMA,
ALTER_SCHEMA,DROP_SCHEMA
TO SERVICE 'ConnectDBA_EventNotificationService'
, '709CD726-2F34-4B67-9AAF-05D0DB31D5A8'
GO