データのアーカイブは、大規模なテーブルを持つ高負荷のOLTPシステムにとって最も重要な課題の一つです。歴史的に、これを実現する最初の試みは非常に単純でした:データはスクリプトまたはアプリケーションを通じて手動で削除またはコピーされました。その後、トランザクション整合性とデータベースの主な作業に与える影響を最小限に抑えることを考慮したより体系的なアプローチが登場しました。
ここでの問題は、情報の物理的な移動だけでなく、一貫性の維持、ブロックの最小化、高いパフォーマンスの確保にも関連しています。アーカイブ時のエラーは、データの損失、ユーザーのブロック、または負荷の大幅な増加を引き起こす可能性があります。
解決策としては、トランザクション制御を伴うバッチ操作の使用や、同一の構造を持つ特別なアーカイブテーブルの形成、またはタスクスケジューラとプロシージャを介した自動化が挙げられます。
コードの例:
-- 1年以上前の5000件のレコードをアーカイブテーブルに移動します INSERT INTO archive_orders SELECT * FROM orders WHERE order_date < DATEADD(year, -1, GETDATE()) AND id IN (SELECT TOP 5000 id FROM orders WHERE order_date < DATEADD(year, -1, GETDATE()) ORDER BY id); DELETE FROM orders WHERE id IN (SELECT TOP 5000 id FROM orders WHERE order_date < DATEADD(year, -1, GETDATE()) ORDER BY id);
主な特徴:
古いレコードの大量削除にはどんなリスクがあり、どう避けるべきですか?
大量削除はロックのエスカレーションを引き起こし、データベース全体の作業を遅延させる可能性があります。これを避けるためには、ループ内で小さな部分で削除を行うか、データベースがサポートしている場合はLIMIT/TOPを使用します。
WHILE 1=1 BEGIN DELETE TOP (1000) FROM orders WHERE order_date < '2023-01-01'; IF @@ROWCOUNT = 0 BREAK; END
アーカイブデータの削除にTRUNCATEを使用できますか?
TRUNCATEはテーブル内のすべての行を削除し、特定の行の条件付きクリアには適していません。トリガーを呼び出さず、WHEREをサポートせず、完全なクリアのためだけに使用され、選択的アーカイブには使用できません。
削除と挿入が異なるトランザクションで行われた場合、移行が正しく行われたことをどう保証しますか?
行を一つのトランザクションで移行するのが最良です:最初にアーカイブにコピーし、その後メインから削除します。そうしないと、操作間での障害が発生した場合に不整合を引き起こす可能性があります。
BEGIN TRANSACTION INSERT INTO archive_orders SELECT * FROM orders WHERE ... DELETE FROM orders WHERE ... COMMIT
エンジニアが業務中にDELETE FROM logs WHERE event_date < '2022-01-01'のスクリプトを1百万件実行します。
利点:
欠点:
5,000行ずつの移行をストアドプロシージャとスケジュールされたタスクを使用して夜間に計画し、各バッチの成功をログに記録します。
利点:
欠点: