Postgresqlで1つのテーブルから別のテーブルに何百万行を効率的にコピーするにはどうすればよいですか?


36

2つのデータベーステーブルがあります。1つには何億ものレコードが含まれています。それを呼び出しましょうhistory。もう1つは毎日計算されるので、すべてのレコードをhistory1つにコピーします。

私がしたことは実行することでした:

INSERT INTO history SELECT * FROM daily

そして、しばらくの間はうまくいきましたが、レコードの数が増え続けるにつれて徐々に遅くなり始めました。今私はからコピーする必要が約2万レコード持っているdailyhistory、単一の操作では、それが完全に時間がかかりすぎます。

あるテーブルから別のテーブルにデータをコピーする別のより効率的な方法はありますか?

回答:


10

長期間(数か月間)履歴を保持する予定がある場合は、パーティションオプションを確認することをお勧めします。日や週ごとに1つのパーティションになります。また、履歴テーブルのアクセスパターンにも依存します(日付を越えてデータにアクセスするクエリを実行しますか?多くの集計などを行います)。集計/要約を保存するためのマテリアライズドビューをご覧ください。 http://www.postgresql.org/docs/9.3/static/ddl-partitioning.html http://www.postgresql.org/docs/9.3/static/sql-creatematerializedview.html


答えてくれてありがとう。行く唯一の方法のようです。データを数か月ごとにパーティション分割し、インデックスの再作成を行う必要があります(ここではインデックスの再生成が問題であったため)。
ミロヴァンゾゴビッチ

16

csv形式でテーブルをダンプします

COPY table TO '/tmp/table.csv' DELIMITER ',';

大量のデータに対してはるかに効率的なCOPYコマンドを使用します。

COPY table FROM '/tmp/table.csv' DELIMITER ',';

詳細については、http: //www.postgresql.org/docs/current/static/sql-copy.htmlでpostgresのドキュメントを確認してください。


1
まだ非常に、非常に遅い...おそらく、そのような巨大なインデックスを再構築しなければならないことで何かをしなければならないのでしょうか?historyテーブルには1億6千万行があり、さらに300万行を追加しています。
ミロバンゾゴヴィッチ

2
空のテーブルをフルにするか、既存の行よりも多くの行を追加する場合、通常、非クラスター化インデックスを削除し、転送が完了したらそれらを再作成する方が効率的です(その時点でテーブルがアクティブに使用されていない場合) )
デビッドスピレット

ところで、これは1回限りの操作ですか、それとも定期的にやらなければならないことですか?定期的にこのトリガーを作成することを提案するので、毎回この試練を経験する必要はありません。
ファブリツィオマッゾーニ

@FabrizioMazzoni-特定の時間に毎日実行する必要があります(スナップショットを適時に取得)。
ミロヴァンゾゴヴィッチ

@DavidSpillett-確かに!インデックス作るの削除(私はデータベースに160Mの行を持っているので)(上記の私の答えを参照)非常に高速なインポートは、しかし、インデックスを再作成することは時間を要する。..
Milovan Zogovic

13

問題はインデックスにありました。historyテーブルには、160Mインデックス付きの列を持っていました。どちらCOPY FROMかを実行するか、INSERT INTO .. SELECT行を挿入するのではなく、インデックスを更新するのに多くの時間がかかりました。インデックスを無効にすると、10秒で3M行をインポートしました。今、私は大きなテーブルのインデックスを再作成するより速い方法を見つける必要があります。


3
履歴テーブルのインデックスも必要ですか?
シャーロック

2
CONCURRENTLYキーワードを使用してインデックスを追加します
Akvel

10

次のように、psqlツールを使用できます。

psql -h ${DAILY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME} -c "copy daily to stdout " | psql -h ${HISTORY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME}  -c "copy history from stdin"

また、シェルスクリプトを作成することもできます。


中間ファイルなしの優れたソリューション。非常に高速で、通常のディスクとネットワークファイルシステム間で1時間20分(インデックスなし)で9億5,000万行のテーブルをコピーしました。
ル・ドロイド

3

もちろん、これは質問に対する正確な答えではありませんが、historyテーブルにアクセスする必要がない場合は、SQLダンプも生成できます。

pg_dump -h host -p port -w -U user db > dump.sql

次に、ツールを使用しgitて差を計算し、これを効率的に保存できます。

git add dump.sql
git commit -m "temp dump"
git gc --aggressive

データベースのほとんどの部分は毎日変更されないため、これは便利です。毎日コピー全体を保存する代わりに、2日間の差を保存できます。

crontabダンプが毎日処理されるようなジョブを使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.