Introdução
Você já enfrentou uma situação em que precisa fazer alterações em um procedimento armazenado ou em uma visualização muito rapidamente? Tenho, muitas vezes, especialmente na fase de implementação. Infelizmente, um sistema de controle de versão não pode ajudar neste caso. Ainda assim, como eu poderia entender que algo foi modificado, e quando?
Este artigo descreve uma possível solução para coleta automática de dados sobre alterações de esquema de banco de dados no MS SQL Server. Como de costume, ficarei feliz em ouvir quaisquer soluções alternativas.
Solução
- Crie duas tabelas:a primeira será para cada banco de dados, a segunda – para todos os bancos de dados:
USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [srv].[ddl_log]( [DDL_Log_GUID] [uniqueidentifier] NOT NULL, [PostTime] [datetime] NOT NULL, [DB_Login] [nvarchar](255) NULL, [DB_User] [nvarchar](255) NULL, [Event] [nvarchar](255) NULL, [TSQL] [nvarchar](max) NULL, CONSTRAINT [PK_ddl_log] PRIMARY KEY CLUSTERED ( [DDL_Log_GUID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO ALTER TABLE [srv].[ddl_log] ADD CONSTRAINT [DF_ddl_log_DDL_Log_GUID] DEFAULT (newid()) FOR [DDL_Log_GUID] GO USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [srv].[ddl_log_all]( [DDL_Log_GUID] [uniqueidentifier] NOT NULL, [Server_Name] [nvarchar](255) NOT NULL, [DB_Name] [nvarchar](255) NOT NULL, [PostTime] [datetime] NOT NULL, [DB_Login] [nvarchar](255) NULL, [DB_User] [nvarchar](255) NULL, [Event] [nvarchar](255) NULL, [TSQL] [nvarchar](max) NULL, [InsertUTCDate] [datetime] NOT NULL, CONSTRAINT [PK_ddl_log_all] PRIMARY KEY CLUSTERED ( [DDL_Log_GUID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO ALTER TABLE [srv].[ddl_log_all] ADD CONSTRAINT [DF_ddl_log_all_DDL_Log_GUID] DEFAULT (newid()) FOR [DDL_Log_GUID] GO ALTER TABLE [srv].[ddl_log_all] ADD CONSTRAINT [DF_ddl_log_all_InsertUTCDate] DEFAULT (getutcdate()) FOR [InsertUTCDate] GO
- Crie um DDL-trigger para um banco de dados que colete mudanças de esquema:
USE [DATABASE_NAME] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TRIGGER [SchemaLog] ON DATABASE --ALL SERVER FOR DDL_DATABASE_LEVEL_EVENTS AS SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; DECLARE @data XML begin try if(CURRENT_USER<>'NT AUTHORITY\NETWORK SERVICE' and SYSTEM_USER<>'NT AUTHORITY\NETWORK SERVICE') begin SET @data = EVENTDATA(); INSERT srv.ddl_log( PostTime, DB_Login, DB_User, Event, TSQL ) select GETUTCDATE(), CONVERT(nvarchar(255), SYSTEM_USER), CONVERT(nvarchar(255), CURRENT_USER), @data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(255)'), @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)') where @data.value('(/EVENT_INSTANCE/EventType)[1]', 'nvarchar(255)') not in('UPDATE_STATISTICS', 'ALTER_INDEX') and @data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)') not like '%Msmerge%'; --there is no need in tracking changes of replication objects end end try begin catch end catch GO SET ANSI_NULLS OFF GO SET QUOTED_IDENTIFIER OFF GO ENABLE TRIGGER [SchemaLog] ON DATABASE GO
Eu recomendo ajustar um filtro e não fazer um DDL-trigger para todo o servidor. É inútil, pois você obterá muitas informações desnecessárias. Nesse caso, é melhor criar um gatilho para cada banco de dados.
No entanto, você terá que desativar esse gatilho durante operações complicadas, por exemplo, replicação. Mas mais tarde, você poderá ligá-lo novamente.
- Você precisará reunir informações em uma única tabela. Por exemplo, você pode fazer isso com uma tarefa no SQL Server Agent uma vez por semana.
- É possível reunir tudo em uma tabela de outra forma que você preferir.
Além disso, recomendo excluir dados antigos.
Resultado
Neste artigo, analisei um exemplo de implementação de uma coleta automática de dados sobre alterações de esquemas de bancos de dados no MS SQL Server. Ele nos permite descobrir o que e quando foi modificado e, se necessário, revertê-los. Em geral, esta solução pode ser útil na fase de implementação onde há muitos erros e quando temos diferentes versões de cópias de bancos de dados a serem analisadas. Se você deseja descobrir o motivo das alterações, pode fazê-lo recuperando um histórico de revisões.
Leia também:
Coleta Automática de Dados sobre Tarefas Concluídas no MS SQL Server