数千万のレコードをプログラムでpostgresデータベースに挿入する必要があります。現在、私は単一の「クエリ」で何千もの挿入ステートメントを実行しています。
これを行うより良い方法はありますか、私が知らないいくつかの一括挿入ステートメントはありますか?
COPYの使用に代わるものがあります。COPYは、Postgresがサポートする複数行の値の構文です。 ドキュメント から:
INSERT INTO films (code, title, did, date_prod, kind) VALUES
('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy');
上記のコードは2行を挿入しますが、準備されたステートメントトークンの最大数に達するまで、任意に拡張できます(999ドルになる可能性がありますが、100%は確信できません)。 COPYを使用できない場合もありますが、これはこれらの状況に代わる価値のあるものです。
処理を高速化する1つの方法は、トランザクション内で複数の挿入またはコピーを明示的に実行することです(たとえば1000)。 Postgresのデフォルトの動作は、各ステートメントの後にコミットするため、コミットをバッチ処理することにより、オーバーヘッドを回避できます。ダニエルの答えのガイドにあるように、これが機能するためには自動コミットを無効にする必要があるかもしれません。また、wal_buffersのサイズを16 MBに増やすことをお勧めする下部のコメントにも注意してください。
UNNEST
配列を持つ関数は、複数行のVALUES構文とともに使用できます。このメソッドはCOPY
を使用するよりも遅いと思いますが、psycopgとpythonを使用する場合に役立ちます(cursor.execute
に渡されるpython list
はpg ARRAY
になります)。
INSERT INTO tablename (fieldname1, fieldname2, fieldname3)
VALUES (
UNNEST(ARRAY[1, 2, 3]),
UNNEST(ARRAY[100, 200, 300]),
UNNEST(ARRAY['a', 'b', 'c'])
);
VALUES
なしで、追加の存在チェックを伴う副選択を使用します。
INSERT INTO tablename (fieldname1, fieldname2, fieldname3)
SELECT * FROM (
SELECT UNNEST(ARRAY[1, 2, 3]),
UNNEST(ARRAY[100, 200, 300]),
UNNEST(ARRAY['a', 'b', 'c'])
) AS temptable
WHERE NOT EXISTS (
SELECT 1 FROM tablename tt
WHERE tt.fieldname1=temptable.fieldname1
);
一括更新と同じ構文:
UPDATE tablename
SET fieldname1=temptable.data
FROM (
SELECT UNNEST(ARRAY[1,2]) AS id,
UNNEST(ARRAY['a', 'b']) AS data
) AS temptable
WHERE tablename.id=temptable.id;
COPY table TO ... WITH BINARY
を使用できます。これは「 テキストおよびCSV形式よりもやや速い 」です。これは、挿入する数百万の行があり、バイナリデータに慣れている場合にのみ行ってください。
それは主に、データベース内の(他の)アクティビティに依存します。このような操作は、他のセッションのためにデータベース全体を効果的に凍結します。別の考慮事項は、データモデルと制約、トリガーなどの存在です。
私の最初のアプローチは常に:ターゲットテーブルに似た構造を持つ(temp)テーブルを作成し(1 = 0のターゲットからテーブルtmp AS select *を作成)、一時テーブルにファイルを読み込むことから始めます。次に、チェックできるものをチェックします。重複、ターゲットにすでに存在するキーなど。
次に、「tmpからターゲットselect *に挿入する」などを実行します。
これが失敗するか、時間がかかりすぎる場合、それを中止し、他の方法(一時的にインデックス/制約を削除するなど)を検討します
私はこの問題に遭遇したばかりで、Postgresへの一括インポートには csvsql をお勧めします。一括挿入を実行するには、単にcreatedb
を使用してから、csvsql
を使用します。これは、データベースに接続し、CSVのフォルダー全体の個別のテーブルを作成します。
$ createdb test
$ csvsql --db postgresql:///test --insert examples/*.csv
ネイティブのlibpqメソッドを使用して、非常に高速なPostgresqデータローダーを実装しました。パッケージを試してみてください https://www.nuget.org/packages/NpgsqlBulkCopy/