Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Raccolta automatica dei dati delle modifiche allo schema del database in MS SQL Server

Introduzione

Ti è mai capitato di affrontare una situazione in cui è necessario apportare modifiche a una stored procedure o a una visualizzazione molto rapidamente? L'ho fatto, molto spesso, soprattutto in fase di attuazione. Sfortunatamente, un sistema di controllo della versione non può aiutare in questo caso. Tuttavia, come posso capire che qualcosa è stato modificato e quando?

Questo articolo descrive una possibile soluzione per la raccolta automatica dei dati sulle modifiche allo schema del database in MS SQL Server. Come al solito, sarò lieto di ascoltare eventuali soluzioni alternative.

Soluzione

  1. Crea due tabelle:la prima sarà per ogni database, la seconda – per tutti i database:
    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. Crea un trigger DDL per un database che raccoglie le modifiche allo schema:
    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

Raccomando di regolare un filtro e di non creare un trigger DDL per l'intero server. È inutile, poiché otterrai molte informazioni inutili. In questo caso, è meglio creare un trigger per ogni database.
Tuttavia, dovrai disattivare questo trigger durante operazioni complicate, ad esempio la replica. Ma in seguito potrai riaccenderlo.

  1. Dovrai raccogliere informazioni in un'unica tabella. Ad esempio, puoi farlo con un'attività in SQL Server Agent una volta alla settimana.
  2. È possibile riunire tutto in una tabella in un altro modo che preferisci.

Inoltre, ti consiglio di eliminare i vecchi dati.

Risultato

In questo articolo, ho analizzato un esempio di implementazione di una raccolta dati automatica sulle modifiche agli schemi dei database in MS SQL Server. Ci consente di scoprire cosa e quando è stato modificato e, se necessario, di ripristinarlo. In generale, questa soluzione può essere utile nella fase di implementazione in cui ci sono molti errori e quando abbiamo diverse versioni di copie di database da analizzare. Se desideri scoprire un motivo per le modifiche, puoi farlo recuperando una cronologia delle revisioni.

Leggi anche:

Raccolta automatica dei dati sulle attività completate in MS SQL Server