2016-03-25 2 views
0

Есть ли какой-либо SQL скрипт для проверки изменений на SQL Server экземпляр, сделанный другим администратором базы данных, и я получаю уведомление по электронной почте об этих изменениях. если да, то, пожалуйста, предоставьте мне сценарий и все шаги для его применения. Я использую SQL Server 2012.Сценарий проверки изменений в экземпляре SQL Server?

ответ

1

Одним из решений является использование DDL trigger, чтобы уловить все изменения схемы (процедуры, функции, определение таблицы и т. Д.). Это может работать для всех незашифрованных объектов, и, конечно же, другие администраторы не должны его отключать.

Подробнее о том, как написать такой триггер и сохранить изменения, можно найти here.

[Позже править]

Я вспомнил, я создал такую ​​проверку на среду разработки, и я могу представить собственную версию, основанную на указанной статье. Помимо обычной информации, я также включил «расстояние» между текстом старого объекта и текстом нового объекта, чтобы иметь общее представление об изменении величины.

1) определение Таблица:

IF OBJECT_ID('dbo.DDLEvents', 'U') IS NULL 
BEGIN 
    CREATE TABLE dbo.DDLEvents 
    (
     EventId   INT IDENTITY(1, 1) NOT NULL, 
     EventDate   DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 
     EventType   NVARCHAR(64), 
     EventXML   XML, 
     DatabaseName  NVARCHAR(255), 
     SchemaName  NVARCHAR(255), 
     ObjectName  NVARCHAR(255), 
     HostName   VARCHAR(128), 
     IPAddress   VARCHAR(32), 
     ProgramName  NVARCHAR(255), 
     LoginName   NVARCHAR(255), 
     ObjectDefinition NVARCHAR(MAX), 
     LastObjDefinition NVARCHAR(MAX), 
     Diff    INT         -- edit distance between last and current object version (gives an idea of how much was changed in the object) 
    ); 

    create index IDX_DDLEvents_Object ON DDLEvents (SchemaName, ObjectName) 
END 
go 

2) Первоначальный текст для существующих объектов:

IF NOT EXISTS(SELECT * FROM dbo.DDLEvents) 
BEGIN 
    INSERT INTO dbo.DDLEvents 
    (EventType, DatabaseName, SchemaName, ObjectName, LoginName, ObjectDefinition) 
    SELECT 'CREATE_PROCEDURE', DB_NAME(), OBJECT_SCHEMA_NAME([object_id]), OBJECT_NAME([object_id]), 'SYSTEM', OBJECT_DEFINITION([object_id]) 
    FROM sys.procedures; 

    INSERT INTO dbo.DDLEvents 
    (EventType, DatabaseName, SchemaName, ObjectName, LoginName, ObjectDefinition) 
    SELECT 'CREATE_VIEW', DB_NAME(), OBJECT_SCHEMA_NAME([object_id]), OBJECT_NAME([object_id]), 'SYSTEM', OBJECT_DEFINITION([object_id]) 
    FROM sys.views; 

    INSERT INTO dbo.DDLEvents 
    (EventType, DatabaseName, SchemaName, ObjectName, LoginName, ObjectDefinition) 
    SELECT 'CREATE_FUNCTION', DB_NAME(), OBJECT_SCHEMA_NAME([object_id]), OBJECT_NAME([object_id]), 'SYSTEM', OBJECT_DEFINITION([object_id]) 
    FROM sys.objects 
    -- scalar, inline table-valued, table-valued 
    WHERE type IN ('FN', 'IF', 'TF') 
END 
go 

3) Расстояние функция (CLR):

[Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = false)] 
public static int Levenshtein(SqlString S1, SqlString S2) 
{ 
    if (S1.IsNull) 
     S1 = new SqlString(""); 

    if (S2.IsNull) 
     S2 = new SqlString(""); 

    int maxLen = 4096; 

    // keeping only the first part of the string (performance reasons) 
    String SC1 = S1.Value.ToUpper(); 
    String SC2 = S2.Value.ToUpper(); 

    if (SC1.Length > maxLen) 
     SC1 = SC1.Remove(maxLen); 
    if (SC2.Length > maxLen) 
     SC2 = SC2.Remove(maxLen); 

    int n = SC1.Length; 
    int m = SC2.Length; 

    short[,] d = new short[n + 1, m + 1]; 
    int cost = 0; 

    if (n + m == 0) 
    { 
     return 0; 
    } 
    else if (n == 0) 
    { 
     return 0; 
    } 
    else if (m == 0) 
    { 
     return 0; 
    } 

    for (short i = 0; i <= n; i++) 
     d[i, 0] = i; 

    for (short j = 0; j <= m; j++) 
     d[0, j] = j; 

    for (int i = 1; i <= n; i++) 
    { 
     for (int j = 1; j <= m; j++) 
     { 
      if (SC1[i - 1] == SC2[j - 1]) 
       cost = 0; 
      else 
       cost = 1; 

      d[i, j] = (short) System.Math.Min(System.Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost); 
     } 
    } 

    // double percentage = System.Math.Round((1.0 - ((double)d[n, m]/(double)System.Math.Max(n, m))) * 100.0, 2); 
    // return percentage; 
    return d[n, m]; 
} 

4) Определение триггера DDL

if not exists (select * from sys.triggers where name = 'DDL_Audit_Trigger') 
    exec ('create trigger DDL_Audit_Trigger ON DATABASE FOR CREATE_PROCEDURE AS BEGIN PRINT 1; END') 
GO 

ALTER TRIGGER [DDL_Audit_Trigger] 
ON DATABASE 
FOR 
    CREATE_ASSEMBLY, ALTER_ASSEMBLY, DROP_ASSEMBLY, 
    CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE, 
    CREATE_FUNCTION, ALTER_FUNCTION, DROP_FUNCTION, 
    CREATE_INDEX, ALTER_INDEX, DROP_INDEX, 
    CREATE_VIEW, ALTER_VIEW, DROP_VIEW, 
    CREATE_ROLE, ALTER_ROLE, DROP_ROLE, 
    CREATE_SCHEMA, ALTER_SCHEMA, DROP_SCHEMA, 
    CREATE_TABLE, ALTER_TABLE, DROP_TABLE, 
    CREATE_TYPE, DROP_TYPE, 
    CREATE_USER, ALTER_USER, DROP_USER, 
    CREATE_TRIGGER, ALTER_TRIGGER, DROP_TRIGGER, 
    RENAME 
AS 
BEGIN 
    SET NOCOUNT ON; 

    BEGIN TRY 
     DECLARE @EventData XML = EVENTDATA(); 
     DECLARE @ip VARCHAR(32) = (SELECT client_net_address FROM sys.dm_exec_connections WHERE session_id = @@SPID); 
     DECLARE @ObjectSchema NVARCHAR(255) = @EventData.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(255)') 
     DECLARE @ObjectName NVARCHAR(255) = @EventData.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(255)') 
     -- DECLARE @ObjectFullName NVARCHAR(255) = @ObjectSchema + '.' + @ObjectName 
     DECLARE @CommandText NVARCHAR(MAX) = @EventData.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'NVARCHAR(MAX)') 

     DECLARE @LastObjectChange DATETIME = (SELECT TOP 1 EventDate FROM dbo.DDLEvents where SchemaName = @ObjectSchema and ObjectName = @ObjectName ORDER BY EventDate DESC) 
     DECLARE @LastObjectDefinition NVARCHAR(MAX) = (SELECT TOP 1 ObjectDefinition FROM dbo.DDLEvents where SchemaName = @ObjectSchema and ObjectName = @ObjectName and EventDate = @LastObjectChange ORDER BY EventDate DESC) 

     INSERT INTO dbo.DDLEvents 
     (EventType, 
      EventXML, DatabaseName, 
      SchemaName, ObjectName, 
      HostName, IPAddress, ProgramName, LoginName, 
      ObjectDefinition, LastObjDefinition, Diff 
     ) 
     SELECT @EventData.value('(/EVENT_INSTANCE/EventType)[1]', 'NVARCHAR(100)'), 
      @EventData, DB_NAME(), 
      @ObjectSchema, @ObjectName, 
      HOST_NAME(), @ip, PROGRAM_NAME(), SUSER_SNAME(), 
      @CommandText, @LastObjectDefinition, dbo.Levenshtein(@CommandText, @LastObjectDefinition); 
    END TRY 
    BEGIN CATCH 
     INSERT INTO dbo.DDLEventsLog (Error) 
     SELECT ERROR_MESSAGE() 
    END CATCH 
END 
GO 
Смежные вопросы