Erweiterte Ereignisse im Vergleich zu SQL Audit - Auswirkungen auf die Leistung

8

Ich möchte ein Audit-Trail-System in meiner Datenbank einrichten, um UPDATE/INSERTAnweisungen für eine bestimmte Tabelle mit sehr hoher Aktivität zu überwachen . Ich habe zwei Möglichkeiten vor mir: Verwenden des in SQL Server integrierten Audit-Systems oder Erweiterte Ereignisse.

Da SQL Server Audit intern erweiterte Ereignisse verwendet, gehe ich davon aus, dass bei der direkten Verwendung von Audit anstelle von erweiterten Ereignissen ein gewisser Overhead entsteht.

Kann ich auf irgendeine Weise testen, welches System den Server stärker beeinflusst? Wenn ich wissen könnte, was tatsächlich passiert, wenn eine XE-Sitzung erstellt wird, würde dies mir bei der Analyse der Auswirkungen auf den Server helfen.

Wir haben Trigger in Betracht gezogen und diese Option wegen des Overheads weggelassen. Dies wurde jedoch nur aufgrund von Informationen aus dem Internet entschieden.

karun_r
quelle
Lassen Sie uns diese Diskussion im Chat fortsetzen .
wBob
Nicht auf alle Ereignisse, die über ein SQL-Audit erfasst werden, kann über XEvents zugegriffen werden. SQL Audit verwendet dieselbe Engine wie XEvents, es handelt sich jedoch um separate Funktionen.
Ja, ich habe davon erfahren. Bei einer Art Lasttest (siehe unten) haben wir jedoch festgestellt, dass XE mehr Overhead als Audit hat. Wenn das Audit XE im Hintergrund verwendet, gibt es eine Idee, warum es mehr Overhead verursacht?
Karun_r

Antworten:

3

Ich habe einen einfachen Prüfstand erstellt, um SQL Server Audit gegen Trigger und möglicherweise andere Optionen zu testen. Bei meinen Tests zum Einfügen von 1 Million Zeilen in eine Tabelle erhielt ich 52, 67 und 159 Sekunden für Baseline, SQL Audit und meinen Trigger:

Testergebnisse

Dies ist nicht besonders wissenschaftlich, bietet Ihnen jedoch möglicherweise eine Möglichkeit, Ansätze zu vergleichen. Sehen Sie sich das Skript an und prüfen Sie, ob es für Sie von Nutzen sein kann:

USE master
GO

SET NOCOUNT ON
GO

IF EXISTS ( SELECT * FROM sys.databases WHERE name = 'testAuditDb' )
ALTER DATABASE testAuditDb SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
IF EXISTS ( SELECT * FROM sys.databases WHERE name = 'testAuditDb' )
DROP DATABASE testAuditDb
GO


CREATE DATABASE testAuditDb
ON PRIMARY
( NAME = N'testAuditDb', FILENAME = N's:\temp\testAuditDb.mdf', SIZE = 1GB, MAXSIZE = UNLIMITED, FILEGROWTH = 128MB )
LOG ON 
( NAME = N'testAuditDb_log', FILENAME = N's:\temp\testAuditDb_log.ldf', SIZE = 100MB, MAXSIZE = 2048GB, FILEGROWTH = 128MB )
GO

ALTER DATABASE testAuditDb SET RECOVERY SIMPLE
GO



------------------------------------------------------------------------------------------------
-- Setup START
------------------------------------------------------------------------------------------------

USE testAuditDb
GO

CREATE SCHEMA auditSchema

-- Create a table
CREATE TABLE auditSchema.auditTable ( 
    rowId INT IDENTITY PRIMARY KEY, 
    someData UNIQUEIDENTIFIER DEFAULT NEWID(), 
    dateAdded DATETIME DEFAULT GETDATE(), 
    addedBy VARCHAR(30) DEFAULT SUSER_NAME(), 
    ts ROWVERSION 
)
GO


-- Setup END
------------------------------------------------------------------------------------------------



------------------------------------------------------------------------------------------------
-- Test 01 - Baseline START
-- Normal timing; no triggers or audits
------------------------------------------------------------------------------------------------


-- Add a million rows to the table and time it.
DECLARE @i INT = 0, @startTime DATETIME2, @endTime DATETIME2

SET @startTime = SYSDATETIME()

WHILE @i < 1000000
BEGIN

    INSERT INTO auditSchema.auditTable DEFAULT VALUES

    SET @i += 1
END

SET @endTime = SYSDATETIME()

SELECT DATEDIFF( second, @startTime, @endTime ) AS baseline
GO


-- Cleanup
TRUNCATE TABLE auditSchema.auditTable 
GO

-- Test 01 - Baseline END
------------------------------------------------------------------------------------------------





------------------------------------------------------------------------------------------------
-- Test 02 - SQL Audit START
-- Try SQL Audit
------------------------------------------------------------------------------------------------

-- Create server audit in master database
USE master
GO

------------------------------------------------------------------------------------------------------------------------
-- The server audit is created with a WHERE clause that limits the server audit to only the auditTable table.
------------------------------------------------------------------------------------------------------------------------
CREATE SERVER AUDIT auditTableAccess TO FILE ( FILEPATH = 'S:\SQLAudit\' ) WHERE object_name = 'auditTable';
GO
ALTER SERVER AUDIT auditTableAccess WITH ( STATE = ON );
GO

-- Create the database audit specification in the testAuditDb database 
USE testAuditDb;
GO

CREATE DATABASE AUDIT SPECIFICATION [dbAudit1]
FOR SERVER AUDIT auditTableAccess
ADD ( 
    SELECT, INSERT, UPDATE ON SCHEMA::[auditSchema]
    BY [public]
    ) WITH ( STATE = ON );
GO


-- Add a million rows to the table and time it.
DECLARE @i INT = 0, @startTime DATETIME2, @endTime DATETIME2

SET @startTime = SYSDATETIME()

WHILE @i < 1000000
BEGIN

    INSERT INTO auditSchema.auditTable DEFAULT VALUES

    SET @i += 1
END

SET @endTime = SYSDATETIME()

SELECT DATEDIFF( second, @startTime, @endTime ) AS sqlAudit
GO


-- Cleanup
TRUNCATE TABLE auditSchema.auditTable
GO
ALTER DATABASE AUDIT SPECIFICATION [dbAudit1] WITH ( STATE = Off );
DROP DATABASE AUDIT SPECIFICATION [dbAudit1]
GO

USE master
ALTER SERVER AUDIT auditTableAccess WITH ( STATE = OFF );

DROP SERVER AUDIT auditTableAccess
GO



/*
-- Inspect the audit output
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp

SELECT *
INTO #tmp
FROM fn_get_audit_file ( 'S:\SQLAudit\auditTableAccess_*.sqlaudit', DEFAULT, DEFAULT );
GO


SELECT statement, MIN(event_time), MAX(event_time), COUNT(*) AS records
FROM #tmp
GROUP BY statement
GO
*/

-- Test 02 - SQL Audit END
------------------------------------------------------------------------------------------------




------------------------------------------------------------------------------------------------
-- Test 03 - Triggers START
-- Trial INSERT/UPDATE trigger with log table
------------------------------------------------------------------------------------------------
USE testAuditDb
GO

CREATE TABLE dbo.auditLog
    (
    auditLogLog     INT IDENTITY PRIMARY KEY,
    schemaName      SYSNAME NOT NULL,
    tableName       SYSNAME NOT NULL,
    dateAdded       DATETIME NOT NULL DEFAULT GETDATE(),
    addedBy         SYSNAME NOT NULL DEFAULT SUSER_NAME(),
    auditXML        XML
    )
GO


-- Generic audit trigger
CREATE TRIGGER trg_dbo__triggerTest ON auditSchema.auditTable
FOR INSERT, UPDATE, DELETE

AS

BEGIN

    IF @@rowcount = 0 RETURN

    SET NOCOUNT ON

    DECLARE @action VARCHAR(10)

    IF EXISTS ( SELECT * FROM inserted )
    AND EXISTS ( SELECT * FROM deleted )
        SET @action = 'UPDATE'
    ELSE IF EXISTS ( SELECT * FROM inserted )
        SET @action = 'INSERT'
    ELSE IF EXISTS ( SELECT * FROM deleted )
        SET @action = 'DELETE'

    INSERT INTO dbo.auditLog ( schemaName, tableName, auditXML )
    SELECT OBJECT_SCHEMA_NAME( parent_id ) schemaName, OBJECT_NAME( parent_id ) tableName,
        (
        SELECT
            @action "@action",
            ( SELECT 'inserted' source, * FROM inserted FOR XML RAW, TYPE ),
            ( SELECT 'deleted' source, * FROM deleted FOR XML RAW, TYPE )
        FOR XML PATH('mergeOutput'), TYPE
        ) x
    FROM sys.triggers
    WHERE OBJECT_ID = @@procid
      AND ( EXISTS ( SELECT * FROM inserted )
         OR EXISTS ( SELECT * FROM deleted )
          )

END
GO


-- Add a million rows to the table and time it.
DECLARE @i INT = 0, @startTime DATETIME2, @endTime DATETIME2

SET @startTime = SYSDATETIME()

WHILE @i < 1000000
BEGIN

    INSERT INTO auditSchema.auditTable DEFAULT VALUES

    SET @i += 1
END

SET @endTime = SYSDATETIME()

SELECT DATEDIFF( second, @startTime, @endTime ) AS triggers
GO

-- Cleanup
TRUNCATE TABLE auditSchema.auditTable
DROP TABLE dbo.auditLog
DROP TRIGGER auditSchema.trg_dbo__triggerTest
GO

-- Test 03 - Triggers END
------------------------------------------------------------------------------------------------

Obwohl die Triggeroption hier nicht sehr gut funktioniert hat, kann mein Triggercode je nach dem, was Sie erfassen möchten, vereinfacht werden, und Sie können auf die alten und neuen Werte in einem ziemlich verwendbaren Format zugreifen, das SQL Audit nicht bietet. Ich habe diese Technik für eine Konfigurationstabelle mit geringerer Aktivität verwendet und sie funktioniert recht gut. Je nachdem, was Sie erfassen möchten, können Sie auch die Datenerfassung ändern in Betracht ziehen .

Lassen Sie mich wissen, wie Sie mit Ihren Prüfungen weitermachen. Viel Glück.

wBob
quelle
3

Ein Vorteil des Audits ist, dass automatisch aufgezeichnet wird, wer es ein- und ausschaltet. XE führt dies nicht sofort aus (obwohl Sie möglicherweise ein Ereignis finden, das das Stoppen / Starten von XE verfolgt). Möglicherweise erfassen die beiden auch unterschiedliche Daten, je nachdem, was Sie genau möchten.

Um einige Tests durchführen zu können, müssten Sie eine Datenbanksicherung durchführen, eine Ablaufverfolgung der Anwendung unter Last erfassen und dann die Kopie wiederherstellen, während Sie eine Wiedergabe / Wiedergabe mit Audit / Ersetzen mit XE durchführen und Leistungsdaten vergleichen.

Welche Leistungsdaten? Es liegt an dir. Für einige Ideen - Linchi Shea führte einen Vergleich zwischen Audit und Trace durch, indem er sich auf Transaktionen / Sek. Konzentrierte, während Kehayias einen Vergleich zwischen Trace und XE durchführte, indem er sich auf Stapel / Sek. Und die gesamte Laufzeit der Wiederholung konzentrierte.

Ich möchte Sie ermutigen, beide und ihre Kommentare zu lesen, da Sie wissen sollten, dass sie unabhängig von Ihrer Tätigkeit interpretiert werden können. Es ist schwierig, einen Apfelvergleich für Äpfel zu bekommen. Außerdem kann eine Ablaufverfolgung / Wiedergabe das Laden möglicherweise nicht richtig simulieren - beispielsweise, wenn Ihre Anwendung viele Massenladevorgänge von nicht mehr vorhandenen Datenträgerdateien ausführt.

Wichtig ist jedoch, dass Sie mindestens eines ausprobieren, damit Sie Ihre Entscheidungen rechtfertigen und auch für den Rest von uns darüber bloggen können.

Cody Konior
quelle
Wenn Sie sagen, dass das Audit die ON / OFF-Audit-Ereignisse automatisch erfasst, sprechen Sie dann über AUSC-Aktionstypen im Audit-Trail? Für ideale Leistungstests sollte ich außerdem die aktuellen Engpässe der Anwendung berücksichtigen und prüfen, ob sie durch Audit oder XE noch schlimmer werden.
Karun_r