迅速に挿入する必要がある大量のデータ(約1300万レコード)を生成するアプリケーションがあります。私はPostgres 9.1でJPA 2.0/Hibernateを使用しており、マルチスレッド化と数千の挿入ごとの挿入のバッチ処理などでかなり優れたパフォーマンス(1秒あたり約25k挿入)を達成し、全体の実行を約8分で完了しました。
ただし、インデックスが欠落している外部キーがいくつかあることに気づきました。これは、分析の観点からデータをドリルダウンするため、および特定の実行までデータを削除するために必要です。残念ながら、これらの3つのインデックスをほとんどの挿入を行うテーブルに追加すると、パフォーマンスは1秒あたり約3kに大幅に低下しました。
このパフォーマンスの低下を回避する方法はありますか?実行前にインデックスを削除し、最後にそれらを再作成することは1つのオプションであることを知っています。別のより不格好なオプションは、代わりにファイル内の最大のテーブルのデータを生成し、COPY
を使用することです。私が知る必要のある外部キー値(シーケンスを通じて生成される)のため、リレーション内の最大のテーブルでしか実行できないと思います。
どちらの方法もハックのようです。他の解決策はありますか、アプリケーションへの侵入が少し少ないかもしれませんか? postgresにインデックス付けやそのようなことを延期するように指示するいくつかの設定?
どんなアイデアも歓迎します。
据え置き索引付けは適切ですが、現在サポートされていません。
インデックスの追加にはコストがかかります-書き込みパフォーマンス。それらはトレードオフです。
COPY
は、インデックスのメンテナンスが主な問題である場合、あまり役に立ちません。
最も簡単な解決策は、インデックスを削除し、インポートが完了したらインデックスを再作成することです。
DBがクラッシュした場合、すべてのデータを失うことに耐えることができるため、次のようなパフォーマンスをさらに改善するための多くのオプションがあります。
fsync=off
上記のいずれかを使用すると、何か問題が発生した場合にデータが失われます。最後のオプションは、ファイルシステムを食べる可能性もあります。
これについては https://stackoverflow.com/questions/9407442/optimise-postgresql-for-fast-testing で詳しく説明しました。
クレイグのアドバイスに加えて、影響を受けるテーブルのストレージパラメータを調べることをお勧めします。
私は現在あなたと同じような状況にあります。私のシステムで最大のテーブルには約2億のレコードが含まれており、パフォーマンスは本当に悪かった。
データベースにいくつかのインデックスを追加するほかに、いくつかのテーブルのストレージパラメータを変更して、テーブル自体のfillfactorのカスタム値andインデックスを指定しました。
Fillfactorにカスタム値を設定すると、各ページでさらに更新するために予約する必要があるスペースの量をPostgreSQLに指示できます。同じことがインデックスにも当てはまります。
詳細は CREATE TABLE のドキュメントと、利用可能な ストレージパラメータ の説明を参照してください。
インフラストラクチャを監視および分析します。 PostgreSQL wiki には、多くの便利なツールがリストされています。
postgresql.conf
ファイルの次の値を変更して、ステートメントロギングを有効にします。
log_min_duration_statement=x
は、xミリ秒より長く実行されるすべてのステートメントをログに記録しますlog_min_messages=level
は、JPAによって生成されたステートメントを理解するのに役立つレベルに詳細は ランタイムロギング構成の説明 を参照してください
pgFounine をインストールして、PostgreSQLログファイルを簡単に分析します。
ストレージパラメータを変更する以外にも、頻繁に実行されるすべてのステートメントを最適化することで、多くのパフォーマンスを実現しました。部分的には、実行ごとに100ミリ秒または50ミリ秒しか獲得しませんでしたが、複雑な操作では合計で5秒以上も獲得しました。