Programmingデータエンジニア

SQLにおける大量データのインポート時に、問題のある行に関する情報を失わないようにエラー処理と失敗操作を分離する方法は?

Hintsage AIアシスタントで面接を突破

回答。

大量データの自動ロードがデータベースで始まったとき、エラー行を記録する必要がすぐに生じました。通常、制約の違反(例えば、データ型の不一致、制約の違反)により、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 + アップロード後の検証と比較すると、性能が著しく低下します。

一般的なエラーとアンチパターン

  • 前もってチェックまたはステージングテーブルなしで大量データのロードを試みると、1つでもエラーが発生した場合に全てのロードがロールバックされます。
  • エラー処理を伴う複数の単一INSERTをループ内で実行すると、ロード速度が大幅に低下し、ロックに悪影響を及ぼします。
  • エラーを外部ファイルのみに記録し、テーブルには記録しないことは、監査と修正の自動化を複雑にします。

事例

ネガティブケース

会社はINSERTスクリプトを介して何万行もロードしていましたが、唯一のキーに関するエラーが発生すると全体のバッチがロールバックされました。これにより、ダウンタイムとデータ損失が生じました。

メリット:

  • 安全性(不正なデータなし)。 デメリット:
  • 時間の浪費、一部保存の不可能、全ファイルの手動修正。

ポジティブケース

ステージングテーブル、エラーロギング、受信データを「有効/無効」に分類することで、インポートを加速し、失敗を保存し自動的に分析できるようになりました。

メリット:

  • 高いパフォーマンス、事前及び事後処理の可能性、エラーに関する透明な報告。 デメリット:
  • ログテーブルとプロセスをサポートするための追加のクエリが必要。