大量データの自動ロードがデータベースで始まったとき、エラー行を記録する必要がすぐに生じました。通常、制約の違反(例えば、データ型の不一致、制約の違反)により、1つのエラー行のために全てのインポートプロセスが中断され、正確なレコードと不正確なレコードの両方を失うことになりました。
問題は、最大限の正確なデータをロードし、今後の手動修正のために監査と詳細なエラー記述を残すことです。単に「全てをロールバックする」という方法ではありません。
解決策: 特定のDBMS(例えば、PostgreSQL、SSISを使用したSQL Server、EXTERNAL TABLESユーティリティを使用したOracle)には、エラー行を分離してロードするメカニズムがあります。普遍的な方法として、ステージングテーブルとOUTER JOINおよびNOT EXISTSを使用したアップロード後の検証、さらに手動で問題行を記録する「ログテーブル」を使用します。
コード例:
-- 1. 一時的なステージングテーブルに全てをロード BULK INSERT staging_payments FROM 'payments.csv' WITH (...) -- 2. 正しいデータをフィルタリング INSERT INTO payments (id, amount, ...) SELECT id, amount, ... FROM staging_payments WHERE amount > 0 AND status IN ('approved', 'pending'); -- 3. エラー行を別のテーブルにログ記録 INSERT INTO import_errors (row_data, error_desc) SELECT *, '不正なステータスまたは負の金額' FROM staging_payments WHERE amount <= 0 OR status NOT IN ('approved', 'pending');
主な特徴:
SQL内でON ERROR RESUME NEXTで全てを実現できますか?
SQL標準には大量操作インポートのためのそのような構文は含まれていません。多くの場合、エラー報告は外部ユーティリティまたは上記のようなログテーブルで生成されます。
エラー行だけをロールバックするためにトランザクションを使用できますか?
トランザクションをロールバックすると、全ての行が一度にロールバックされます(原子性)。部分的な保存は、最初にステージングテーブルにロードし、その後手動で成功した行をコミットし、不成功な行をログに記録する場合のみ可能です。
なぜ各行に対してTRY/CATCHでINSERTをエラー捕獲するのが非効率的なのですか?
何百万行を逐次的に処理することは、単一のINSERT + TRY/CATCHにより、バッチまたはBULK INSERT + アップロード後の検証と比較すると、性能が著しく低下します。
会社はINSERTスクリプトを介して何万行もロードしていましたが、唯一のキーに関するエラーが発生すると全体のバッチがロールバックされました。これにより、ダウンタイムとデータ損失が生じました。
メリット:
ステージングテーブル、エラーロギング、受信データを「有効/無効」に分類することで、インポートを加速し、失敗を保存し自動的に分析できるようになりました。
メリット: