サードパーティのトランザクションデータベースによって作成された監査レコードを格納するテーブルdsStaging.Audit
を持つSQL Serverソリューションがあります。これらの監査を使用して、サードパーティシステムからのCRUD操作をSQLデータベースに同期します。
CREATE TABLE [dsStaging].[Audit](
[SyncExecutionId] [bigint] NOT NULL,
[AuditDataGuid] [nvarchar](56) NOT NULL,
[AuditDate] [datetime] NOT NULL,
[AuditDateTimeZone] [datetimeoffset](3) NULL,
[AuditEventGroup] [nvarchar](56) NOT NULL,
[TransactionId] [bigint] NOT NULL,
[TransactionSequence] [int] NOT NULL,
.
...
.
CONSTRAINT [PK_Audit] PRIMARY KEY CLUSTERED
(
[SyncExecutionId] ASC,
[TransactionId] ASC,
[TransactionSequence] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
監査が処理されたら、監査レコードを別のテーブルProcessed.Audit
に移動して、x日後に削除できるようにします。
CREATE TABLE [Processed].[Audit](
[SyncExecutionId] [bigint] NOT NULL,
[AuditDataGuid] [nvarchar](56) NOT NULL,
[AuditDate] [datetime] NOT NULL,
[AuditEventGroup] [nvarchar](56) NOT NULL,
[TransactionId] [bigint] NOT NULL,
[TransactionSequence] [int] NOT NULL,
.
...
.
CONSTRAINT [PK_Processed_Audit] PRIMARY KEY NONCLUSTERED
(
[AuditDate] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
監査をステージングからプロセスに移すことにおける私の主な目的はパフォーマンスです。ステージングテーブルが可能な限り短時間ロックされるようにして、未処理の監査をできるだけ早く処理できるようにする必要があります(ステージングテーブルの監査が少ない=処理がはるかに高速)。
約1.5mの監査レコードこのプロセスを実行中毎時約10kのバッチで調べています。
監査の移動プロセスは、約20〜30秒ごとに実行されます。 Processed.Audit
レコードを削除するプロセスは1時間ごとに実行され、X日前(通常は約7日)から1時間分の監査を削除します。
Processed.Audit
テーブルをクラスター化インデックスに変換する必要がありますか?サポートされる最小バージョン:SQL Server 2012 Standard Edition。
このシナリオでクラスター化インデックスが必要になる主な理由は、次の行です。
プロセスを削除するプロセス。監査レコードは1時間ごとに実行され、x日前(通常は約7日)から1時間分の監査を削除します。
HEAPから行を削除すると、削除によってテーブルロックが取得されるか、削除クエリにWITH (TABLOCK)
ヒントが提供されない限り、データページの割り当てが解除されない場合があります。ただし、それが並行性に何をもたらすかは想像できるでしょう。良くない。
RCSIまたはスナップショットアイソレーションを使用している場合、TABLOCK
ヒントはこの動作を行わないことに注意してください。
これは簡単な例です。小さなテーブルをロードします。
USE tempdb;
SET NOCOUNT ON;
CREATE TABLE dbo.heap
(
id INT PRIMARY KEY NONCLUSTERED,
junk VARCHAR(1000)
);
INSERT dbo.heap (
id, junk )
SELECT TOP 1000 x.n, REPLICATE('A', x.n % 1000)
FROM (
SELECT ROW_NUMBER() OVER ( ORDER BY @@ROWCOUNT ) AS n
FROM sys.messages AS m ) AS x;
健全性チェッククエリを実行して、ヒープと非クラスター化PKに割り当てられているページ数を把握します。
SELECT OBJECT_NAME(i.object_id) AS table_name,
i.name AS index_name,
MAX(a.used_pages) AS leaf_me_alone
FROM sys.indexes AS i
JOIN sys.partitions AS p
ON p.object_id = i.object_id
AND p.index_id = i.index_id
JOIN sys.allocation_units AS a
ON a.container_id = p.partition_id
WHERE OBJECT_NAME(i.object_id) = 'heap'
GROUP BY i.object_id, i.index_id, i.name
ORDER BY OBJECT_NAME(i.object_id), i.index_id;
この結果:
table_name index_name leaf_me_alone
heap NULL 74
heap PK__heap__ 7
つまり、ヒープに74ページ、NC PKに7ページです。
シングルトン削除をいくつか実行して、テーブルをクリアします。
DECLARE @i INT = 1;
WHILE @i < 1000
BEGIN
DELETE h
FROM dbo.heap AS h
WHERE h.id = @i;
SET @i += 1;
PRINT @i;
END;
健全性チェッククエリを再実行すると、同じ結果が得られます。
さらに悪いことに、ここでテーブルをクエリすると、SQLは ALL OF THOSE BLANK PAGES !を読み取ります。
SET STATISTICS TIME, IO ON
SELECT *
FROM dbo.heap AS h;
テーブル「ヒープ」。スキャンカウント1、論理読み取り67
したがって、テーブルが人為的に大きくなるだけでなく、SQLのディスク、メモリ、バックアップ、およびDBCC CHECKDBにも多数の空白ページができるようになりました。
1時間ごとにこのプロセスを通過する約150万の監査レコードを調べています。
ヘヘヘヘ!楽しくない。
ヒープからページの割り当てを解除するためのその他のオプションは次のとおりです。
TRUNCATE TABLE dbo.heap
データを一括削除する必要があるため、これは機能しません。
ALTER TABLE dbo.heap REBUILD;
これは、テーブルのすべての非クラスター化インデックスを同時に再構築するため、そのテーブルサイズでは苦痛です。
テーブルはページを再利用しますか?たぶんちょっとかもしれない。
DECLARE @id_max INT = (SELECT MAX(id) FROM dbo.heap AS h);
INSERT dbo.heap (
id, junk )
SELECT TOP 5000 x.n + @id_max, REPLICATE('A', x.n % 1000)
FROM (
SELECT ROW_NUMBER() OVER ( ORDER BY @@ROWCOUNT ) AS n
FROM sys.messages AS m ) AS x;
サニティーチェック:
table_name index_name leaf_me_alone
heap NULL 400
heap PK__heap__ 20
SELECT *クエリ:
テーブル「ヒープ」。スキャンカウント1、論理読み取り392
お役に立てれば!
私はそれを別の方法で行います:
dsStaging.Audit
。sp_rename
を使用して、レコードを中央のテーブルに移動します。スイッチパーティション機能を使用して、process.Audit
テーブルと中間テーブルからパーティション分割することを検討します。