Eventos extendidos vs Auditoría SQL - implicaciones de rendimiento

8

Me gustaría configurar un tipo de sistema de seguimiento de auditoría en mi base de datos para monitorear las UPDATE/INSERTdeclaraciones en una tabla específica con una actividad muy alta. Tengo dos opciones frente a mí: usar el sistema de auditoría incorporado de SQL Server o ir con eventos extendidos.

Como SQL Server Audit usa internamente eventos extendidos, supongo que habrá algún tipo de sobrecarga cuando use Auditoría en lugar de eventos extendidos directamente.

¿Hay alguna forma de hacer algunas pruebas para analizar qué sistema está afectando más al servidor? Si pudiera saber qué sucede realmente cuando se crea una sesión XE, me ayudaría a analizar el impacto en el servidor.

Consideramos los desencadenantes y omitimos esa opción debido a la sobrecarga. Pero eso se decidió basándose en información de Internet.

karun_r
fuente
Continuemos esta discusión en el chat .
wBob
No se puede acceder a todos los eventos que se capturan a través de una Auditoría SQL a través de XEvents. SQL Audit utiliza el mismo motor detrás de XEvents, pero son características separadas.
Sí, vino a saber sobre eso. Pero cuando hicimos algún tipo de prueba de carga (ver más abajo), observamos que XE tiene más gastos generales que Auditoría. Si la auditoría usa XE en segundo plano, ¿alguna idea de por qué está causando más sobrecarga?
karun_r

Respuestas:

3

Creé una plataforma de prueba simple para probar SQL Server Audit contra los desencadenantes y, potencialmente, otras opciones. En mis pruebas de insertar 1 millón de filas en una tabla obtuve 52, 67 y 159 segundos para la línea de base, Auditoría SQL y mi disparador respectivamente:

Resultados de la prueba

Ahora, esto no es particularmente científico, pero potencialmente le ofrece una forma de comparar enfoques. Eche un vistazo a la secuencia de comandos, vea si puede serle útil:

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

Si bien la opción de activación no funcionó muy bien aquí, mi código de activación podría simplificarse dependiendo de lo que desea capturar y le permite acceder a los valores antiguos y nuevos en un formato bastante utilizable que SQL Audit no. He usado esta técnica para una tabla de configuración de menor actividad y funciona bastante bien. Dependiendo de lo que desee capturar, también podría considerar Cambiar captura de datos .

Déjame saber cómo te va con tus pruebas. Buena suerte.

wBob
fuente
3

Un beneficio de la Auditoría que viene a la mente es que registrará automáticamente quién lo enciende y apaga, XE no lo hará de forma inmediata (aunque puede encontrar un evento que rastrea XE stop / start). También puede encontrar que los dos capturan datos diferentes, dependiendo de exactamente lo que desee.

Con respecto a hacer algunas pruebas, necesitaría tener una copia de seguridad de la base de datos, capturar un rastro de la aplicación bajo carga y luego restaurar la copia mientras realiza una reproducción / reproducción con auditoría / reemplazo con XE y compara los datos de rendimiento.

¿Qué datos de rendimiento? Tu decides. Para algunas ideas, Linchi Shea hizo una comparación entre Auditoría y Rastreo al enfocarse en Transacciones / segundo, mientras que Kehayias hizo una comparación entre Rastreo y XE al enfocarse en lotes / segundo y tiempo de ejecución general de repetición.

Te animo a leer ambos y sus comentarios porque debes saber que no importa lo que hagas, estará abierto a interpretación. Es difícil obtener una comparación de manzanas por manzanas. Además, un seguimiento / reproducción puede fallar al simular la carga correctamente, por ejemplo, cuando su aplicación está haciendo muchas cargas masivas de archivos de disco que ya no existen.

Pero lo importante es que intentes al menos una cosa, para que puedas justificar tus decisiones, y también bloguear sobre eso para el resto de nosotros.

Cody Konior
fuente
Cuando dice que la auditoría capturará automáticamente los eventos de ENCENDIDO / APAGADO de la auditoría, ¿está hablando de los tipos de acción AUSC en la pista de auditoría? Además, para una prueba de rendimiento ideal, creo que debería considerar los cuellos de botella actuales de la aplicación y ver si la auditoría o XE los están empeorando.
karun_r