Peristiwa diperpanjang vs SQL Audit - implikasi kinerja

8

Saya ingin mengatur sistem audit trail pada database saya untuk memonitor UPDATE/INSERTpernyataan pada tabel tertentu dengan aktivitas yang sangat tinggi. Saya memiliki dua opsi di depan saya: menggunakan sistem Audit bawaan SQL Server atau menggunakan Extended Events.

Sebagai SQL Server Audit secara internal menggunakan Extended Events, saya berasumsi akan ada semacam overhead ketika saya menggunakan Audit daripada Extended Events secara langsung.

Apakah ada cara saya bisa melakukan beberapa pengujian untuk menganalisis sistem mana yang lebih berdampak pada server? Jika saya bisa tahu apa yang sebenarnya terjadi ketika sesi XE dibuat, itu akan membantu saya dalam menganalisis dampak pada server.

Kami mempertimbangkan pemicu dan mengabaikan opsi itu karena overhead. Tetapi itu baru saja diputuskan berdasarkan informasi dari Internet.

karun_r
sumber
Tidak semua peristiwa yang ditangkap melalui Audit SQL dapat diakses melalui XEvents. SQL Audit menggunakan mesin yang sama di belakang XEvents, tetapi mereka adalah fitur yang terpisah.
Ya. Aku tahu tentang itu. Tetapi ketika kami melakukan semacam pengujian beban (lihat di bawah), kami mengamati bahwa XE memiliki lebih banyak overhead daripada Audit. Jika audit menggunakan XE di latar belakang, tahu mengapa itu menyebabkan lebih banyak overhead?
karun_r

Jawaban:

3

Saya membuat rig uji sederhana untuk mengadili SQL Server Audit terhadap pemicu, dan kemungkinan opsi lainnya. Dalam pengujian saya memasukkan 1 juta baris ke dalam tabel saya mendapat 52, 67 dan 159 detik untuk baseline, SQL Audit dan pemicu saya masing-masing:

Hasil tes

Sekarang ini tidak terlalu ilmiah tetapi berpotensi menawarkan Anda satu cara untuk membandingkan pendekatan. Lihat skripnya, lihat apakah itu bisa berguna bagi Anda:

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

Sementara opsi pemicu tidak bekerja dengan baik di sini, kode pemicu saya dapat disederhanakan tergantung pada apa yang ingin Anda tangkap dan itu memungkinkan Anda akses ke nilai-nilai lama dan baru dalam format yang cukup dapat digunakan yang SQL Audit tidak. Saya telah menggunakan teknik ini untuk tabel konfigurasi aktivitas yang lebih rendah dan itu bekerja dengan cukup baik. Bergantung pada apa yang ingin Anda tangkap, Anda juga dapat mempertimbangkan Ubah Pengambilan Data .

Biarkan saya tahu bagaimana Anda melanjutkan cobaan Anda. Semoga berhasil.

wBob
sumber
3

Salah satu manfaat Audit yang terlintas dalam pikiran adalah bahwa ia akan secara otomatis merekam siapa yang menyalakan dan mematikannya, XE tidak akan melakukannya di luar kotak (meskipun Anda mungkin menemukan acara yang melacak berhenti / mulainya XE). Anda juga dapat menemukan bahwa keduanya menangkap data yang berbeda, tergantung pada apa yang Anda inginkan.

Mengenai melakukan beberapa pengujian, Anda harus memiliki cadangan basis data, menangkap jejak aplikasi yang sedang dimuat, dan kemudian mengembalikan salinan sambil melakukan replay / replay dengan audit / ganti dengan XE dan membandingkan data kinerja.

Data kinerja apa? Terserah kamu. Untuk beberapa ide - Linchi Shea melakukan perbandingan antara Audit dan Trace dengan berfokus pada Transaksi / detik, sementara Kehayias melakukan perbandingan antara Trace dan XE dengan berfokus pada batch / detik dan runtime replay keseluruhan.

Saya mendorong Anda untuk membaca keduanya dan komentar mereka karena Anda harus tahu bahwa apa pun yang Anda lakukan itu akan terbuka untuk interpretasi. Sulit mendapatkan apel untuk perbandingan apel. Juga, jejak / replay dapat gagal mensimulasikan memuat dengan benar - misalnya ketika aplikasi Anda melakukan banyak beban massal dari file disk yang tidak ada lagi.

Tetapi yang penting adalah Anda mencoba setidaknya satu hal, sehingga Anda dapat membenarkan keputusan Anda, dan juga blog tentang hal itu untuk kita semua.

Cody Konior
sumber
Ketika Anda mengatakan bahwa audit akan secara otomatis menangkap peristiwa ON / OFF audit, apakah Anda berbicara tentang jenis tindakan AUSC dalam jejak audit? Juga, untuk pengujian kinerja yang ideal, saya kira saya harus mempertimbangkan hambatan aplikasi saat ini dan melihat apakah audit atau XE memperburuknya.
karun_r