Eventos estendidos vs Auditoria SQL - implicações de desempenho

8

Gostaria de configurar um tipo de sistema de trilha de auditoria no meu banco de dados para monitorar UPDATE/INSERTinstruções em uma tabela específica com atividade muito alta. Tenho duas opções à minha frente: usando o sistema de auditoria interno do SQL Server ou vá com Eventos estendidos.

Como a Auditoria do SQL Server usa internamente Eventos Estendidos, presumo que haverá algum tipo de sobrecarga quando usar Auditoria em vez de Eventos Estendidos diretamente.

Existe alguma maneira de fazer alguns testes para analisar qual sistema está impactando mais o servidor? Se eu pudesse saber o que realmente acontece quando qualquer sessão XE é criada, isso me ajudaria a analisar o impacto no servidor.

Consideramos gatilhos e deixamos de fora essa opção por causa de sobrecarga. Mas isso foi decidido com base em informações da Internet.

karun_r
fonte
Nem todos os eventos capturados por meio de uma auditoria SQL são acessíveis pelo XEvents. A auditoria do SQL utiliza o mesmo mecanismo por trás do XEvents, mas são recursos separados.
Sim. Veio a saber sobre isso. Porém, quando fizemos algum tipo de teste de carga (veja abaixo), observamos que o XE tem mais sobrecarga do que a auditoria. Se a auditoria usa o XE em segundo plano, alguma idéia de por que está causando mais sobrecarga?
karun_r

Respostas:

3

Criei uma plataforma de teste simples para testar a Auditoria do SQL Server contra gatilhos e potencialmente outras opções. Nos meus testes de inserção de 1 milhão de linhas em uma tabela, obtive 52, 67 e 159 segundos para a linha de base, a Auditoria SQL e meu gatilho, respectivamente:

Resultado dos testes

Agora, isso não é particularmente científico, mas potencialmente oferece uma maneira de comparar abordagens. Dê uma olhada no script, veja se ele pode ser útil para você:

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

Embora a opção de gatilho não tenha se saído muito bem aqui, meu código de gatilho pode ser simplificado dependendo do que você deseja capturar e permite acessar os valores antigos e novos em um formato bastante utilizável que o SQL Audit não faz. Eu usei essa técnica para uma tabela de configuração de atividade mais baixa e funciona muito bem. Dependendo do que você deseja capturar, você também pode considerar o Change Data Capture .

Deixe-me saber como você continua suas tentativas. Boa sorte.

wBob
fonte
3

Um benefício da Auditoria que vem à mente é que ela grava automaticamente quem a liga e desliga, o XE não fará isso imediatamente (embora você possa encontrar um evento que rastreie a parada / partida do XE). Você também pode descobrir que os dois capturam dados diferentes, dependendo exatamente do que você deseja.

Ao fazer alguns testes, você precisaria ter um backup do banco de dados, capturar um rastreio do aplicativo sob carga e restaurar a cópia enquanto fazia uma repetição / repetição com auditoria / substituição com o XE e comparando dados de desempenho.

Quais dados de desempenho? Você decide. Para algumas idéias - Linchi Shea fez uma comparação entre Audit e Trace, concentrando-se em Transações / s, enquanto Kehayias fez uma comparação entre Trace e XE, concentrando-se em lotes / s e no tempo de execução geral da reprodução.

Encorajo-vos a ler ambos e seus comentários, porque você deve saber que, não importa o que faça, estará aberto à interpretação. É difícil conseguir maçãs para comparação de maçãs. Além disso, um rastreamento / reprodução pode falhar ao simular a carga corretamente - por exemplo, quando seu aplicativo está realizando muitas cargas em massa de arquivos de disco que não existem mais.

Mas o importante é que você tente pelo menos uma coisa, para poder justificar suas decisões e também publicar um blog sobre isso para o resto de nós.

Cody Konior
fonte
Quando você diz que a auditoria captura automaticamente os eventos ON / OFF de auditoria, você está falando sobre os tipos de ação AUSC na trilha de auditoria? Além disso, para um teste de desempenho ideal, acho que devo considerar os gargalos atuais do aplicativo e ver se a auditoria ou o XE os estão piorando.
26416 karun_r