Eventi estesi e audit SQL: implicazioni sulle prestazioni


8

Vorrei impostare un tipo di sistema di audit trail sul mio database per monitorare le UPDATE/INSERTdichiarazioni su una tabella specifica con attività molto elevate. Ho due opzioni davanti a me: usare il sistema di controllo integrato di SQL Server o andare con Eventi estesi.

Poiché SQL Server Audit utilizza internamente gli Eventi estesi, suppongo che ci sarà un qualche tipo di sovraccarico quando uso direttamente Audit invece degli Eventi estesi.

Esiste un modo per eseguire alcuni test per analizzare quale sistema ha un impatto maggiore sul server? Se potessi sapere cosa succede effettivamente quando viene creata una sessione XE, mi aiuterebbe ad analizzare l'impatto sul server.

Abbiamo considerato i trigger e lasciato fuori quell'opzione a causa del sovraccarico. Ma questo è stato appena deciso sulla base di informazioni provenienti da Internet.



Non tutti gli eventi acquisiti tramite un controllo SQL sono accessibili tramite XEvents. SQL Audit utilizza lo stesso motore dietro XEvents, ma sono funzionalità separate.

Sì, è venuto a saperlo. Ma quando abbiamo fatto una sorta di test di carico (vedi sotto), abbiamo osservato che XE ha un overhead maggiore di Audit. Se l'audit utilizza XE in background, hai idea del perché sta causando più sovraccarico?
karun_r,

Risposte:


3

Ho creato un semplice banco di prova per provare SQL Server Audit contro i trigger e potenzialmente altre opzioni. Nei miei test per l'inserimento di 1 milione di righe in una tabella ho ottenuto rispettivamente 52, 67 e 159 secondi per la baseline, SQL Audit e il mio trigger:

Risultati del test

Ora questo non è particolarmente scientifico ma potenzialmente ti offre un modo per confrontare gli approcci. Dai un'occhiata allo script, vedi se può esserti utile:

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
------------------------------------------------------------------------------------------------

Mentre l'opzione di trigger non ha funzionato molto bene qui, il mio codice di trigger potrebbe essere semplificato a seconda di ciò che si desidera acquisire e ti consente di accedere ai valori vecchi e nuovi in ​​un formato abbastanza utilizzabile che SQL Audit non fa. Ho usato questa tecnica per una tabella di configurazione a bassa attività e funziona abbastanza bene. A seconda di ciò che desideri acquisire, puoi anche prendere in considerazione Change Data Capture .

Fammi sapere come vai avanti con le tue prove. In bocca al lupo.


3

Un vantaggio dell'Audit che viene in mente è che registrerà automaticamente chi lo accende e si spegne, XE non lo farà immediatamente (anche se potresti trovare un evento che tiene traccia dell'arresto / avvio di XE). Potresti anche scoprire che i due acquisiscono dati diversi, in base esattamente a ciò che desideri.

Per quanto riguarda l'esecuzione di alcuni test, è necessario disporre di un backup del database, acquisire una traccia dell'applicazione sotto carico, quindi ripristinare la copia mentre si esegue una riproduzione / riproduzione con controllo / sostituzione con XE e confronto dei dati sulle prestazioni.

Quali dati sulle prestazioni? Tocca a voi. Per alcune idee - Linchi Shea ha fatto un confronto tra Audit e Trace concentrandosi su Transazioni / sec, mentre Kehayias ha fatto un confronto tra Trace e XE concentrandosi su batch / sec e tempo di riproduzione generale.

Ti incoraggio a leggere entrambi e i loro commenti perché dovresti sapere che, qualunque cosa tu faccia, sarà aperto all'interpretazione. È difficile ottenere una mela per il confronto delle mele. Inoltre, una traccia / riproduzione potrebbe non riuscire a simulare correttamente il carico, ad esempio quando l'applicazione sta eseguendo molti carichi di massa da file su disco che non esistono più.

Ma la cosa importante è che provi almeno una cosa, in modo da poter giustificare le tue decisioni e anche blog su di esso per il resto di noi.


Quando dici che l'audit acquisirà automaticamente gli eventi ON / OFF dell'audit, stai parlando dei tipi di azione AUSC nella pista di audit? Inoltre, per un test delle prestazioni ideale, suppongo che dovrei considerare gli attuali colli di bottiglia dell'applicazione e vedere se il controllo o XE li stanno peggiorando.
karun_r,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.