sql >> Database >  >> RDS >> Sqlserver

Automatische gegevensverzameling van wijzigingen in het databaseschema in MS SQL Server

Inleiding

Heeft u wel eens te maken gehad met een situatie waarin u zeer snel wijzigingen moet aanbrengen in een opgeslagen procedure of een weergave? Ik heb dat heel vaak, vooral in de implementatiefase. Helaas kan een versiebeheersysteem in dit geval niet helpen. Maar hoe kan ik begrijpen dat er iets is gewijzigd, en wanneer?

Dit artikel beschrijft een mogelijke oplossing voor het automatisch verzamelen van gegevens over wijzigingen in het databaseschema in MS SQL Server. Zoals gewoonlijk hoor ik graag alternatieve oplossingen.

Oplossing

  1. Maak twee tabellen:de eerste is voor elke database, de tweede - voor alle databases:
    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. Maak een DDL-trigger voor een database die schemawijzigingen verzamelt:
    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

Ik raad aan om een ​​filter aan te passen en geen DDL-trigger voor de hele server te maken. Het is nutteloos, omdat je veel onnodige informatie krijgt. In dit geval is het beter om voor elke database een trigger aan te maken.
U zult deze trigger echter moeten uitschakelen tijdens gecompliceerde bewerkingen, bijvoorbeeld replicatie. Maar later kunt u het weer aanzetten.

  1. U moet informatie in één tabel verzamelen. U kunt het bijvoorbeeld één keer per week doen met een taak in de SQL Server Agent.
  2. Het is mogelijk om alles in één tabel te verzamelen op een andere manier die u verkiest.

Daarnaast raad ik aan om oude gegevens te verwijderen.

Resultaat

In dit artikel heb ik een voorbeeld geanalyseerd van het implementeren van een automatische gegevensverzameling over wijzigingen van databaseschema's in MS SQL Server. Het stelt ons in staat om te achterhalen wat en wanneer is gewijzigd en, indien nodig, terug te draaien. Over het algemeen kan deze oplossing nuttig zijn in de implementatiefase waar er veel fouten zijn en wanneer we verschillende versies van databasekopieën moeten analyseren. Als u een reden voor wijzigingen wilt achterhalen, kunt u dit doen door een revisiegeschiedenis op te halen.

Lees ook:

Automatische gegevensverzameling over voltooide taken in MS SQL Server


  1. Hoe krijg ik alleen numerieke kolomwaarden?

  2. Hoe ontkom ik aan vierkante haken in een LIKE-clausule?

  3. Hoe DATE_ADD() werkt in MariaDB

  4. MySQL-query om kolomnamen te krijgen?