SQLで大量のデータを処理するには、メモリのオーバーフローやロックを防ぎ、安定したパフォーマンスを確保するために特別なアプローチが必要です。主な手法の一つは、操作をバッチに分割することです。入力データは小さな部分で処理されるため、サーバーへの負荷が軽減され、トランザクションやエラー発生時のロールバックをより良く制御できます。
重要なポイント:
ROWCOUNTまたはLIMIT / TOP)COMMITを実行し、トランザクションログを軽減する例(SQL Server):
DECLARE @BatchSize INT = 1000; WHILE 1 = 1 BEGIN BEGIN TRANSACTION; DELETE TOP(@BatchSize) FROM BigLogTable WHERE CreatedDate < '2021-01-01'; IF @@ROWCOUNT = 0 BREAK; COMMIT TRANSACTION; END
パフォーマンスに最小限の影響を与えて100百万件のレコードを大きなテーブルから削除するにはどうすればいいですか?
不正解: 「一度に大きなDELETEをする」。
正解: バッチサイズを制御しながら少しずつ削除し、各ブロックごとにCOMMITを行い、必要に応じてディスクの負荷やロックを減らすために遅延(WAITFOR DELAYなど)を使用します。
例(PostgreSQL):
DO $$ BEGIN LOOP DELETE FROM big_table WHERE created_at < NOW() - interval '1 year' LIMIT 10000; EXIT WHEN NOT FOUND; COMMIT; END LOOP; END$$;
物語
プロジェクト: 高負荷な銀行サービス。 エラー: 開発者が80百万行の古いログを一度の大きなクエリで削除した。結果 — トランザクションログがテラバイトに増加し、すべてのディスクスペースが不足し、サービスが「ダウン」した。
物語
プロジェクト: 在庫管理システムを持つオンラインショップ。 エラー: 大量挿入時にトランザクションのサイズが制限されなかった。大きなバッチのインポート中にエラーが発生し、以前の作業をすべてロールバックしてやり直す必要があり、数時間かかることになった。
物語
プロジェクト: 小売業者、注文の詳細を記録するデータベース。 エラー: バッチを使用したが、イテレーション間でCOMMITを忘れた — トランザクションログが指数関数的に増加し、サーバーが「遅く」なり、その後、標準の手段でのログの緊急クリーニングが必要になった。