Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Collecte automatique de données des modifications de schéma de base de données dans MS SQL Server

Présentation

Avez-vous déjà été confronté à une situation où vous deviez apporter très rapidement des modifications à une procédure stockée ou à une vue ? J'ai, très souvent, surtout au stade de la mise en œuvre. Malheureusement, un système de contrôle de version ne peut pas aider dans ce cas. Pourtant, comment pourrais-je comprendre que quelque chose a été modifié, et quand ?

Cet article décrit une solution possible pour la collecte automatique de données sur les modifications de schéma de base de données dans MS SQL Server. Comme d'habitude, je serai heureux d'entendre toute solution alternative.

Solution

  1. Créez deux tables :la première sera pour chaque base de données, la seconde pour toutes les bases :
    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. Créez un déclencheur DDL pour une base de données qui collecte les modifications de schéma :
    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

Je recommande d'ajuster un filtre et de ne pas créer de déclencheur DDL pour l'ensemble du serveur. C'est inutile, car vous obtiendrez beaucoup d'informations inutiles. Dans ce cas, il est préférable de créer un déclencheur pour chaque base de données.
Cependant, vous devrez désactiver ce déclencheur lors d'opérations compliquées, par exemple la réplication. Mais plus tard, vous pourrez le rallumer.

  1. Vous devrez rassembler des informations dans un seul tableau. Par exemple, vous pouvez le faire avec une tâche dans l'Agent SQL Server une fois par semaine.
  2. Il est possible de tout rassembler dans un tableau d'une autre manière que vous préférez.

De plus, je recommande de supprimer les anciennes données.

Résultat

Dans cet article, j'ai analysé un exemple d'implémentation d'une collecte automatique de données sur les changements de schémas de bases de données dans MS SQL Server. Cela nous permet de savoir quoi et quand a été modifié et, si nécessaire, de les annuler. En général, cette solution peut être utile au stade de la mise en œuvre où il y a beaucoup d'erreurs et lorsque nous avons différentes versions de copies de bases de données à analyser. Si vous souhaitez connaître la raison des modifications, vous pouvez le faire en récupérant un historique des révisions.

Lire aussi :

Collecte automatique de données sur les tâches terminées dans MS SQL Server