sql >> Base de Datos >  >> RDS >> Sqlserver

Recopilación automática de datos de cambios en el esquema de la base de datos en MS SQL Server

Introducción

¿Alguna vez se ha enfrentado a una situación en la que necesita realizar cambios en un procedimiento almacenado o en una vista muy rápidamente? Tengo, muy a menudo, especialmente en la etapa de implementación. Desafortunadamente, un sistema de control de versiones no puede ayudar en este caso. Aún así, ¿cómo podría entender que algo ha sido modificado y cuándo?

Este artículo describe una posible solución para la recopilación automática de datos sobre los cambios en el esquema de la base de datos en MS SQL Server. Como de costumbre, estaré encantado de escuchar cualquier solución alternativa.

Solución

  1. Cree dos tablas:la primera será para cada base de datos, la segunda, para todas las bases de datos:
    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
  2. Cree un activador DDL para una base de datos que recopile los cambios 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

Recomiendo ajustar un filtro y no hacer un disparador DDL para todo el servidor. Es inútil, ya que obtendrá mucha información innecesaria. En este caso, es mejor crear un activador para cada base de datos.
Sin embargo, deberá desactivar este activador durante operaciones complicadas, por ejemplo, la replicación. Pero más tarde, podrá volver a encenderlo.

  1. Deberá recopilar información en una sola tabla. Por ejemplo, puede hacerlo con una tarea en el Agente SQL Server una vez a la semana.
  2. Es posible reunir todo en una mesa de otra manera que prefiera.

Además, recomiendo eliminar los datos antiguos.

Resultado

En este artículo, analicé un ejemplo de implementación de una recopilación automática de datos sobre cambios de esquemas de bases de datos en MS SQL Server. Nos permite saber qué y cuándo se han modificado y, en caso necesario, revertirlas. En general, esta solución puede ser útil en la etapa de implementación donde hay muchos errores y cuando tenemos diferentes versiones de copias de bases de datos para analizar. Si desea averiguar el motivo de los cambios, puede hacerlo recuperando un historial de revisiones.

Lea también:

Recopilación automática de datos sobre tareas completadas en MS SQL Server