質問の背景:
データのバルク更新は、移行、マイグレーション、ビジネスロジックの修正時に必要とされます。典型的な例として、サービスを停止せず、可用性とパフォーマンスを保ちながら、作業テーブルの数千万行のステータスを変更する必要があります。
問題:
制限のない通常の更新 (UPDATE) は時間がかかり、ロックのエスカレーションを引き起こす可能性があり、テーブルをロックしてエラー時には全体のロールバックを引き起こします。ユーザーへの影響を最小限に抑え、トランザクション性を確保するアプローチが求められます。
解決策:
コード例:
-- 10,000 行ごとのバッチ更新の例 WHILE 1 = 1 BEGIN UPDATE TOP (10000) mytable SET status = 'archived', updated = GETDATE() WHERE status = 'active'; IF @@ROWCOUNT = 0 BREAK; END
主な特徴:
バルク更新を1つのトランザクションで行い、テーブルをロックせずに済むか?
通常は不可能です。大きなトランザクションはテーブルやページをロックし、ロックやタイムアウトのリスクを高めます。バッチ処理で作業する方が良いです。
インデックスの有無はバルク更新の速度に影響するか?
はい。インデックス付きフィールドの更新は各行に対してインデックスの再構築を必要とします。一時的にインデックスを削除することが有益な場合もありますが、これは深い分析を必要とします。
バッチ更新時にすべての行は原子的に更新されるか?
いいえ、原子性はバッチ内でのみ保証されます(行/トランザクションの制限)。バッチが中断された場合、一部の行が更新され、一部は更新されません。真の原子性が必要な場合は、1つのトランザクションでの完全な更新が必要ですが、大量のデータに対しては危険です。
技術者が、本番DBで10百万行を1つのクエリで更新しようとした:UPDATE mytable SET status = 'archived'。サイトが「固まり」、ロールバックに数十分かかり、パフォーマンスが低下しました。
利点:
クエリは10,000行ごとのバッチに分割され、短いトランザクションで実行され、本番中にダウンタイムなしで更新が行われます。
利点: