2016-03-19 28 views
0

ユーザ指定の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ファイルからすべての行を読み取り、作成したいです一致するレコードがrecipientssubmissionsテーブルに存在することを確認してください。

これらのテーブルにデータをロードする最も効率的な方法は何でしょうか?

これは主に概念的な質問です。具体的な実装を求めているわけではありません。


  • まず第一に、私は単純に読み、解析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.jsSequelizeKnexを使用して私のアプリを書いていますが、具体的な技術はここではあまり関係ありません。

+0

データをロードし、一時テーブルに、あなたが必要なSQL/PostgreSQLの任意の機能を使用します。 – Abelisto

+2

COPY(http://www.postgresql.org/docs/9.5/static/sql-copy.html)コマンドに精通していますか?それを一時テーブルに持ち込んだ後、挿入を使用してデスティネーションテーブルを作成します。(COPYは標準のSQL btwではありません) –

+0

'COPY'を使うのが最速の方法です。参照してください:http://stackoverflow.com/questions/33271377/postgres-csv-copy-from-import-is-not-respecting-csv-headers –

答えて

0

pgAdminには、1.16以降のデータインポート用のGUIがあります。まずテーブルを作成してから、データを簡単にインポートすることができます。テーブル名を右クリックし、「インポート」をクリックします。

enter image description here

enter image description here

+0

私はいくつかのサードパーティのグラフィカルツールを使用することはできません。私は自分のアプリケーションを通して、あるいは少なくとも何らかのAPIを介してこれを行う必要があります。 –