58

私はbulk_createを使用して、数千または行をpostgresqlDBにロードしています。残念ながら、一部の行がIntegrityErrorを引き起こし、bulk_createプロセスを停止しています。djangoにそのような行を無視して、できるだけ多くのバッチを保存するように指示する方法があるかどうか疑問に思いました。

4

7 に答える 7

9

(注:私はDjangoを使用していないため、より適切なフレームワーク固有の回答があるかもしれません)

INSERTPostgreSQL は最初のエラーでトランザクション全体を中止するため、Django が失敗を単に無視することによってこれを行うことはできません。

Django には、次のいずれかの方法が必要です。

  1. INSERT各行を個別のトランザクションで処理し、エラーを無視します (非常に遅い)。
  2. 各挿入の前に を作成しますSAVEPOINT(スケーリングの問題が発生する可能性があります)。
  3. 行がまだ存在しない場合にのみ、手順またはクエリを使用して挿入します (複雑で時間がかかります)。また
  4. データをテーブルに一括挿入するか、(より良い)COPYデータをTEMPORARYテーブルにマージし、それをサーバー側のメイン テーブルにマージします。

upsert のようなアプローチ (3) は良いアイデアのように思えますが、upsert と insert-if-not-exists は驚くほど複雑です。

UNLOGGED個人的には、(4) を採用します: 新しい別のテーブル (おそらくまたは) に一括挿入し、TEMPORARY手動の SQL を実行して次のことを行います。

LOCK TABLE realtable IN EXCLUSIVE MODE;

INSERT INTO realtable 
SELECT * FROM temptable WHERE NOT EXISTS (
    SELECT 1 FROM realtable WHERE temptable.id = realtable.id
);

LOCK TABLE ... IN EXCLUSIVE MODEは、行を作成する同時挿入が、上記のステートメントによって実行された挿入と競合して失敗するのを防ぎます。、、およびのみの同時実行は妨げられないため、テーブルからの読み取りは通常どおり続行されます。SELECTSELECT ... FOR UPDATEINSERTUPDATEDELETE

同時書き込みを長時間ブロックする余裕がない場合は、代わりに書き込み可能な CTE を使用して行の範囲を から にコピーtemptablerealtable、失敗した場合は各ブロックを再試行することができます。

于 2012-09-17T02:03:29.827 に答える