ユーザ指定のCSVファイルからPostgreSQLデータベーステーブルにデータをロードする必要があるアプリケーションがあります。CSVファイルからPostgreSQLデータベースにデータをロード
CSVファイルの構造が簡単である:私は3つのテーブル持っているデータベースで
name,email
John Doe,[email protected]
...
:
---------------
-- CAMPAIGNS --
---------------
CREATE TABLE "campaigns" (
"id" serial PRIMARY KEY,
"name" citext UNIQUE CHECK ("name" ~ '^[-a-z0-9_]+$'),
"title" text
);
----------------
-- RECIPIENTS --
----------------
CREATE TABLE "recipients" (
"id" serial PRIMARY KEY,
"email" citext UNIQUE CHECK (length("email") <= 254),
"name" text
);
-----------------
-- SUBMISSIONS --
-----------------
CREATE TYPE "enum_submissions_status" AS ENUM (
'WAITING',
'SENT',
'FAILED'
);
CREATE TABLE "submissions" (
"id" serial PRIMARY KEY,
"campaignId" integer REFERENCES "campaigns" ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
"recipientId" integer REFERENCES "recipients" ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
"status" "enum_submissions_status" DEFAULT 'WAITING',
"sentAt" timestamp with time zone
);
CREATE UNIQUE INDEX "submissions_unique" ON "submissions" ("campaignId", "recipientId");
CREATE INDEX "submissions_recipient_id_index" ON "submissions" ("recipientId");
を私は指定されたCSVファイルからすべての行を読み取り、作成したいです一致するレコードがrecipients
とsubmissions
テーブルに存在することを確認してください。
これらのテーブルにデータをロードする最も効率的な方法は何でしょうか?
これは主に概念的な質問です。具体的な実装を求めているわけではありません。
まず第一に、私は単純に読み、解析CSVファイルの行ごとに、それぞれのE-Mailの
SELECT/INSERT
クエリを発行しようとしました。明らかに、1分あたり〜4kのレコードをロードできる非常に遅い解決策でしたが、コードはかなりシンプルで簡単でした。ここでは、CSVファイルを1行ずつ読み込んでいますが、すべての電子メールを1千の要素のバッチに集約しています。すべての
SELECT/INSERT
クエリは、SELECT id, email WHERE email IN ('...', '...', '...', ...)
構成を使用してバッチで行われます。そのようなアプローチはパフォーマンスを向上させました。今では1分あたり〜25kレコードのパフォーマンスがあります。しかし、このアプローチでは、かなり複雑なマルチステップコードが必要でした。
この問題を解決し、さらに優れたパフォーマンスを得るための方策はありますか?
ここで重要な問題は、私が最初にrecipients
テーブルにデータを挿入する必要があり、その後、私はsubmissions
テーブルに対応するレコードを作成するために生成されたid
を使用する必要があるということです。
また、挿入されたEメールが一意であることを確認する必要があります。今では、アプリケーション内に単純な配列ベースのインデックスを使用して、重複する電子メールがバッチに追加されないようにしています。
Node.js
とSequelize
とKnex
を使用して私のアプリを書いていますが、具体的な技術はここではあまり関係ありません。
データをロードし、一時テーブルに、あなたが必要なSQL/PostgreSQLの任意の機能を使用します。 – Abelisto
COPY(http://www.postgresql.org/docs/9.5/static/sql-copy.html)コマンドに精通していますか?それを一時テーブルに持ち込んだ後、挿入を使用してデスティネーションテーブルを作成します。(COPYは標準のSQL btwではありません) –
'COPY'を使うのが最速の方法です。参照してください:http://stackoverflow.com/questions/33271377/postgres-csv-copy-from-import-is-not-respecting-csv-headers –