sql >> Databasteknik >  >> RDS >> Sqlserver

Automatisk datainsamling av databasschemaändringar i MS SQL Server

Introduktion

Har du någonsin ställts inför en situation där du behöver göra ändringar i en lagrad procedur eller en vy mycket snabbt? Jag har, väldigt ofta, särskilt på genomförandestadiet. Tyvärr kan ett versionskontrollsystem inte hjälpa i detta fall. Ändå, hur kunde jag förstå att något har ändrats, och när?

Den här artikeln beskriver en möjlig lösning för automatisk datainsamling om databasschemaändringar i MS SQL Server. Som vanligt kommer jag gärna höra eventuella alternativa lösningar.

Lösning

  1. Skapa två tabeller:den första kommer att vara för varje databas, den andra – för alla databaser:
    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. Skapa en DDL-utlösare för en databas som samlar in schemaändringar:
    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

Jag rekommenderar att du justerar ett filter och inte gör en DDL-trigger för hela servern. Det är värdelöst, eftersom du kommer att få mycket onödig information. I det här fallet är det bättre att skapa en trigger för varje databas.
Du måste dock stänga av denna trigger under komplicerade operationer, till exempel replikering. Men senare kommer du att kunna slå på den igen.

  1. Du måste samla information i en enda tabell. Du kan till exempel göra det med en uppgift i SQL Server Agent en gång i veckan.
  2. Det är möjligt att samla allt i en tabell på ett annat sätt som du föredrar.

Dessutom rekommenderar jag att du tar bort gamla data.

Resultat

I den här artikeln har jag analyserat ett exempel på att implementera en automatisk datainsamling om förändringar av databasscheman i MS SQL Server. Det låter oss ta reda på vad och när som har ändrats, och, om nödvändigt, att återställa dem. I allmänhet kan den här lösningen vara till hjälp vid implementeringsstadiet där det finns många misstag och när vi har olika versioner av databaser kopior som ska analyseras. Om du vill ta reda på en anledning till ändringar kan du göra det genom att hämta en revisionshistorik.

Läs även:

Automatisk datainsamling om slutförda uppgifter i MS SQL Server


  1. SQL Server på Linux

  2. Avancerad SQL:Variationer och olika användningsfall av T-SQL Insert Statement

  3. Hur man hanterar skottsekunder i Oracle

  4. LN() Funktion i Oracle