私はbulk_createを使用して、数千または行をpostgresqlDBにロードしています。残念ながら、一部の行がIntegrityErrorを引き起こし、bulk_createプロセスを停止しています。djangoにそのような行を無視して、できるだけ多くのバッチを保存するように指示する方法があるかどうか疑問に思いました。
7 に答える
(注:私はDjangoを使用していないため、より適切なフレームワーク固有の回答があるかもしれません)
INSERT
PostgreSQL は最初のエラーでトランザクション全体を中止するため、Django が失敗を単に無視することによってこれを行うことはできません。
Django には、次のいずれかの方法が必要です。
INSERT
各行を個別のトランザクションで処理し、エラーを無視します (非常に遅い)。- 各挿入の前に を作成します
SAVEPOINT
(スケーリングの問題が発生する可能性があります)。 - 行がまだ存在しない場合にのみ、手順またはクエリを使用して挿入します (複雑で時間がかかります)。また
- データをテーブルに一括挿入するか、(より良い)
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
は、行を作成する同時挿入が、上記のステートメントによって実行された挿入と競合して失敗するのを防ぎます。、、およびのみの同時実行は妨げられないため、テーブルからの読み取りは通常どおり続行されます。SELECT
SELECT ... FOR UPDATE
INSERT
UPDATE
DELETE
同時書き込みを長時間ブロックする余裕がない場合は、代わりに書き込み可能な CTE を使用して行の範囲を から にコピーtemptable
しrealtable
、失敗した場合は各ブロックを再試行することができます。