トリガー、および場合によっては他のオプションに対してSQL Server Auditを試行するための簡単なテストリグを作成しました。テーブルに100万行を挿入するテストでは、ベースライン、SQL監査、およびトリガーにそれぞれ52秒、67秒、159秒かかりました。
これは特に科学的ではありませんが、アプローチを比較する1つの方法を提供する可能性があります。スクリプトを確認し、それがあなたに役立つかどうかを確認してください:
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
------------------------------------------------------------------------------------------------
ここでトリガーオプションはうまく機能しませんでしたが、キャプチャしたい内容に応じてトリガーコードを簡略化できます。これにより、SQL監査では使用できないかなり使いやすい形式で古い値と新しい値にアクセスできます。アクティビティの少ない構成テーブルにこの手法を使用しましたが、非常にうまく機能します。何をキャプチャしたいかに応じて、変更データキャプチャを検討することもできます。
試練をどのように進めるか教えてください。幸運を。