[解決済み】PostgreSQLで挿入のパフォーマンスを高速化する方法
質問
Postgresの挿入パフォーマンスをテストしています。データ型が数値のカラムを1つ持つテーブルがあります。このテーブルには、インデックスもあります。このクエリを使ってデータベースを満杯にしました。
insert into aNumber (id) values (564),(43536),(34560) ...
上記のクエリで400万行を一度に1万行ずつ非常に高速に挿入しました。データベースが600万行に達した後、パフォーマンスは15分毎に100万行に激減しました。挿入パフォーマンスを向上させるコツはありますか?このプロジェクトでは、最適な挿入パフォーマンスが必要なのです。
5GBのRAMを搭載したマシンでWindows 7 Proを使用しています。
解決方法は?
参照 データベースを作成する は、PostgreSQLのマニュアルに記載されています。 depeszさんの秀逸な例文 というトピックと このSOの質問 .
(この回答は、既存のDBにデータを一括ロードする、または新規にDBを作成する場合についてであることに注意してください。でのDBリストアパフォーマンスに興味があるのであれば
pg_restore
または
psql
の実行
pg_dump
を出力する場合、この多くは適用されません。
pg_dump
と
pg_restore
は、スキーマ+データのリストア終了後にトリガーやインデックスの作成などをすでに行っています)
.
やることはたくさんあるんです。理想的な解決策は、インポートを
UNLOGGED
テーブルをインデックスなしで使用し、それをログに記録するように変更してインデックスを追加します。残念ながら、PostgreSQL 9.4では、テーブルをログ付きに変更するためのサポートはありません。
UNLOGGED
をログに残すことができます。9.5では
ALTER TABLE ... SET LOGGED
を使えば、このようなことが可能になります。
一括インポートのためにデータベースをオフラインにできる場合は
pg_bulkload
.
それ以外の場合
-
テーブル上のすべてのトリガーを無効にする
-
インポート開始前にインデックスを削除し、インポート後にインデックスを再作成してください。(その際 だいぶ 一度にインデックスを作成する方が、同じデータを徐々に追加していくよりも時間がかからず、出来上がったインデックスもずっとコンパクトになります)。
-
単一のトランザクション内でインポートを行う場合、コミットする前に外部キー制約を削除し、インポートを行い、制約を再作成することは安全です。インポートが複数のトランザクションにまたがっている場合は、無効なデータを取り込む可能性があるため、この操作を行わないでください。
-
可能であれば
COPY
の代わりにINSERT
s -
を使用できない場合
COPY
を使用することを検討してください。INSERT
を使用することができます。もうやっているようですね。を並べようとしないでください。 も 多くの値を1つのVALUES
しかし、これらの値はメモリに数回分収まらなければならないので、1ステートメントあたり数百個に抑えてください。 -
明示的なトランザクションに挿入をバッチ化し、1トランザクションあたり数十万から数百万回の挿入を行います。AFAIKでは、実用的な制限はありませんが、バッチ処理を行うことで、入力データに各バッチの開始をマークすることにより、エラーから回復することができます。繰り返しになりますが、あなたはすでにこれを実行しているようです。
-
使用方法
synchronous_commit=off
と、巨大なcommit_delay
を使用して、fsync() のコストを削減します。しかし、これは大きなトランザクションに作業を分割している場合にはあまり役に立ちません。 -
INSERT
またはCOPY
を複数の接続から並列に接続します。接続数はハードウェアのディスクサブシステムに依存します。経験則では、直接接続型ストレージを使用する場合、物理的なハードドライブごとに1つの接続が必要です。 -
を高く設定します。
max_wal_size
値(checkpoint_segments
を有効にしてください。log_checkpoints
. PostgreSQLのログを見て、チェックポイントがあまりにも頻繁に発生することに不満を抱いていないことを確認してください。 -
インポート中にシステムがクラッシュした場合、PostgreSQLクラスタ全体(あなたのデータベースと同じクラスタ上の他のデータベース)を壊滅的な破壊で失っても構わない場合のみ、Pgを停止させることができます。
fsync=off
を設定し、Pg を起動し、インポートを行い、その後(極めて重要なことですが)Pg を停止してfsync=on
をもう一度。参照 WAL設定 . PostgreSQLのインストール先のデータベースに気になるデータが既にある場合は、この操作を行わないでください。 を設定した場合fsync=off
を設定することができます。full_page_writes=off
ただし、データベースの破損やデータの損失を防ぐため、インポート後はこの機能をオンに戻してください。参照 非耐久性設定 のマニュアルを参照してください。
また、システムのチューニングも視野に入れておく必要があります。
-
使用する 良品 ストレージはなるべくSSDを。信頼性が高く、電源保護されたライトバックキャッシュを備えた優れたSSDは、コミットレートを信じられないほど高速化します。上記のアドバイスに従えば、ディスクのフラッシュ回数や、ディスクの交換回数が減るので、あまりメリットはありません。
fsync()
しかし、それでも大きな助けになることは間違いありません。データの保存を気にしないのでなければ、適切な電源障害対策のない安価なSSDを使用しないでください。 -
ダイレクトアタッチドストレージにRAID 5またはRAID 6を使用している場合、今すぐ停止してください。データをバックアップし、RAIDアレイをRAID 10に再構築して、もう一度試してみてください。RAID 5/6 は大量書き込みのパフォーマンスには絶望的です - 大きなキャッシュを持つ優れた RAID コントローラが役立ちますが。
-
もし、バッテリバックアップされた大きなライトバックキャッシュを持つハードウェアRAIDコントローラを使用するオプションがあれば、多くのコミットを行うワークロードの書き込みパフォーマンスを本当に向上させることができます。コミット遅延のある非同期コミットや、バルクロード中の大きなトランザクションが少ない場合は、あまり役に立ちません。
-
可能であれば、WALを保存する(
pg_wal
またはpg_xlog
を別のディスク/ディスクアレイで使用することができます。同じディスクで別のファイルシステムを使用する意味はほとんどない。人々はしばしばWALにRAID1ペアを使用することを選択します。繰り返しますが、これはコミット率の高いシステムでより効果を発揮します。また、データロードのターゲットとしてログのないテーブルを使用する場合は、ほとんど効果がありません。
こちらもご覧ください 高速テストのためのPostgreSQLの最適化 .
関連
-
[解決済み] Oracle(LiveSQL)のSQL [重複]について
-
[解決済み] SQL ServerでSELECTからUPDATEする方法とは?
-
[解決済み] PHPでSQLインジェクションを防ぐにはどうしたらいいですか?
-
[解決済み] PostgreSQLの場合。PostgreSQLのテーブルを表示する
-
[解決済み] PostgreSQLの "DESCRIBE TABLE"
-
[解決済み] PostgreSQL コマンドラインユーティリティ: psql を終了する方法
-
[解決済み] PostgreSQLのユーザーパスワードを変更する方法を教えてください。
-
[解決済み] どのバージョンのPostgreSQLを使用していますか?
-
[解決済み] PostgreSQLからのPL/pgSQL出力をCSVファイルに保存する
-
[解決済み】Mac OS XでPostgreSQLサーバーを起動するには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】SQL Server サブクエリが1つ以上の値を返しました。サブクエリが =, !=, <, <= , >, >= に続く場合、これは許可されません。
-
[解決済み】INTERSECTとINNER JOINは根本的に違うのか?[重複している]
-
[解決済み] テスト
-
[解決済み】sys.dm_exec_sql_textはどのように機能するのでしょうか?
-
[解決済み] ora-06553 pls-306 'ogc_x' の呼び出しで引数の数または種類が誤っている。
-
[解決済み] Oracle(LiveSQL)のSQL [重複]について
-
[解決済み] varchar 値の変換で int カラムがオーバーフローしました。
-
[解決済み] SQLエラーです。ORA-00922: オプションがないか無効です。
-
[解決済み】Postgresに一括挿入を行う最速の方法は何ですか?
-
[解決済み】高速テストのためのPostgreSQLの最適化