典型的なRailsアプリケーションのために、SQLiteからPostgreSQLに切り替えています。
問題は、PGで仕様の実行が遅くなったことです。
SQLiteでは〜34秒かかりましたが、PGでは〜76秒で、2倍以上遅いです。
そこで、いくつかのテクニックをに適用し、コードを変更せずに仕様のパフォーマンスをSQLiteと同等にします(接続オプションを設定するだけで、おそらく不可能です)。
私の頭の上からの明白な事柄のカップルは次のとおりです:
ご存知かもしれませんが、私は信頼性とそれ以外のことは気にしません(DBはここではただの捨てものです)。
PGを最大限に活用し、できる限り速くにする必要があります。
ベストアンサーは、理想的には、それを行うためのtricksを説明し、それらのトリックのセットアップと欠点を説明します。
PDATE:fsync = off
+ full_page_writes = off
は、時間を〜65秒(〜-16秒)に減らしただけです。良いスタートですが、34の目標からはほど遠いです。
PDATE 2:I RAM diskを使用しようとしました しかし、パフォーマンスの向上はエラーマージン内でした。そのため、価値があるとは思えません。
PDATE 3:*最大のボトルネックが見つかりましたが、現在の仕様はSQLiteの仕様と同じくらい高速に実行されます。
問題は切り捨てを行ったデータベースのクリーンアップでした。どうやらSQLiteの速度が速すぎるようです。
それを「修正」するには、各テストの前にトランザクションを開き、最後にロールバックします。
〜700テストのいくつかの数値。
SQLiteの2倍の速度向上。 PGの速度が4倍になりました。
まず、常に最新バージョンのPostgreSQLを使用します。パフォーマンスの改善は常に行われているため、古いバージョンをチューニングしている場合はおそらく時間を無駄にしているでしょう。たとえば、 PostgreSQL 9.2はTRUNCATE
の速度を大幅に改善し、もちろんインデックスのみのスキャンを追加します。マイナーリリースでも常に従う必要があります。 バージョンポリシー を参照してください。
Doではなく、RAMdiskまたはその他の非永続ストレージにテーブルスペースを置きます 。
表領域が失われると、データベース全体が破損し、大きな作業なしで使用するのが困難になる場合があります。 UNLOGGED
テーブルを使用し、とにかくキャッシュ用にRAMをたくさん持つことに比べると、これにはほとんど利点がありません。
本当にramdiskベースのシステムが必要な場合は、initdb
ramdisk上の新しいPostgreSQLインスタンスをinitdb
ingすることにより、ramdisk上のまったく新しいクラスターになります。したがって、完全に破棄可能なPostgreSQLインスタンスができます。
テスト時には、 非耐久性で高速な動作 用にサーバーを構成できます。
これは、PostgreSQLの fsync=off
設定の唯一の許容可能な使用法の1つです。この設定は、PostgreSQLに、順序付けられた書き込みや、その他の厄介なデータ整合性保護やクラッシュ安全性のものを気にせず、電源が切れたりOSがクラッシュした場合にデータを完全に破棄する許可を与えます。
言うまでもなく、Pgを他の場所から再生成できるデータの一時データベースとして使用していない限り、本番環境でfsync=off
を有効にしないでください。 fsyncをオフにしようとしている場合にのみ、 full_page_writes
をオフにすることもできます。 fsync=off
とfull_page_writes
はclusterレベルで適用されるため、PostgreSQLインスタンスのallデータベースに影響することに注意してください。
実稼働で使用する場合は、synchronous_commit=off
を使用してcommit_delay
を設定できます。これは、fsync=off
と同じ利点の多くを、巨大なデータ破損のリスクなしに得ることができるためです。非同期コミットを有効にすると、最近のデータが少し失われますが、それだけです。
DDLをわずかに変更するオプションがある場合、Pg 9.1+のUNLOGGED
テーブルを使用して、WALロギングを完全に回避し、サーバーがクラッシュした場合にテーブルが消去されるという犠牲を払って実際の速度を上げることもできます。すべてのテーブルのログを記録しないようにする構成オプションはありません。CREATE TABLE
中に設定する必要があります。テストに適していることに加えて、安全である必要があるものが含まれているデータベースに生成されたデータまたは重要でないデータでいっぱいのテーブルがある場合に便利です。
ログを確認し、チェックポイントが多すぎるという警告が表示されているかどうかを確認します。もしそうなら、 checkpoint_segments を増やす必要があります。また、checkpoint_completion_targetを調整して書き込みをスムーズにすることもできます。
ワークロードに合わせてshared_buffers
を調整します。これはOSに依存し、マシンで他に何が起こっているかに依存し、試行錯誤が必要です。デフォルトは非常に控えめです。 PostgreSQL 9.2以前でshared_buffers
を増やす場合、OSの最大共有メモリ制限を増やす必要がある場合があります。 9.3以降では、共有メモリの使用方法を変更して、それを回避しました。
多くの作業を行う接続を2、3個だけ使用している場合は、work_mem
を増やして、並べ替えなどに使用するRAMを増やします。work_mem
設定が高すぎると、メモリ不足の問題が発生する可能性がありますこれは、接続ごとではなくソートごとであるため、1つのクエリがネストされたソートを多数持つことができるためです。reallyは、EXPLAIN
でディスクに流出するソートを確認できる場合、または work_mem
設定 で記録される場合(推奨)、log_temp_files
を増やす必要があります、しかし、より高い値は、Pgがよりスマートな計画を選択できるようにする場合もあります。
ここで別のポスターで述べたように、可能であればxlogとメインテーブル/インデックスを別々のHDDに置くのが賢明です。個別のパーティションはかなり無意味です。本当に個別のドライブが必要です。 fsync=off
を使用して実行している場合、この分離によるメリットははるかに少なく、UNLOGGED
テーブルを使用している場合はほとんどありません。
最後に、クエリを調整します。 random_page_cost
およびseq_page_cost
がシステムのパフォーマンスを反映していること、effective_cache_size
が正しいことなどを確認してください。EXPLAIN (BUFFERS, ANALYZE)
を使用して個々のクエリプランを調べ、auto_explain
モジュールをオンにしてすべての低速クエリを報告します。適切なインデックスを作成するか、コストパラメータを調整するだけで、クエリのパフォーマンスを劇的に向上させることができます。
私の知る限り、データベースまたはクラスタ全体をUNLOGGED
として設定する方法はありません。そうすることができるのは面白いでしょう。 PostgreSQLメーリングリストで質問することを検討してください。
オペレーティングシステムレベルで実行できるチューニングもいくつかあります。あなたがしたい主なことは、オペレーティングシステムがディスクへの書き込みを積極的にフラッシュしないことを確信させることです。
Linuxでは、 virtual memory subsystem のdirty_*
のようなdirty_writeback_centisecs
設定でこれを制御できます。
ライトバック設定の調整が緩すぎる唯一の問題は、他のプログラムによるフラッシュにより、PostgreSQLのすべての蓄積バッファもフラッシュされ、すべてが書き込みでブロックされている間に大きなストールを引き起こす可能性があることです。別のファイルシステムでPostgreSQLを実行することでこれを軽減できる場合がありますが、一部のフラッシュはファイルシステムレベルではなくデバイスレベルまたはホスト全体レベルであるため、それに頼ることはできません。
このチューニングでは、実際にワークロードに最適なものを確認するために設定をいじる必要があります。
新しいカーネルでは、vm.zone_reclaim_mode
をゼロに設定することをお勧めします。これは、PostgreSQLがshared_buffers
を管理する方法との相互作用により、NUMAシステム(最近のほとんどのシステム)で深刻なパフォーマンス問題を引き起こす可能性があるためです。
これらはコードの変更が必要なものです。彼らはあなたに合わないかもしれません。いくつかはあなたが適用できるかもしれないものです。
作業をより大きなトランザクションにバッチ処理しない場合は、開始します。小さなトランザクションの多くは高価であるため、可能な限り実用的であれば、バッチ処理を行う必要があります。非同期コミットを使用している場合、これはそれほど重要ではありませんが、それでも強くお勧めします。
可能な限り一時テーブルを使用します。 WALトラフィックを生成しないため、挿入および更新の速度が大幅に向上します。大量のデータを一時テーブルに丸lurみし、必要に応じて操作してから、INSERT INTO ... SELECT ...
を実行して最終テーブルにコピーする価値がある場合があります。一時テーブルはセッションごとです。セッションが終了するか接続が失われると、一時テーブルはなくなり、他の接続はセッションの一時テーブルの内容を見ることができなくなります。
PostgreSQL 9.1以降を使用している場合は、セッション状態など、失うことのできるデータに UNLOGGED
テーブルを使用できます。これらは異なるセッションで表示され、接続間で保持されます。サーバーが不意にシャットダウンして再作成できないものには使用できない場合は切り捨てられますが、キャッシュ、マテリアライズドビュー、状態テーブルなどには最適です。
一般に、DELETE FROM blah;
は使用しないでください。代わりにTRUNCATE TABLE blah;
を使用してください。テーブル内のすべての行をダンプする方がはるかに高速です。可能であれば、1回のTRUNCATE
呼び出しで多くのテーブルを切り捨てます。ただし、TRUNCATES
の小さなテーブルを何度も繰り返し使用する場合は注意が必要です。参照: Postgresql切り捨て速度
外部キーにインデックスがない場合、それらの外部キーによって参照される主キーを含むDELETE
sは恐ろしく遅くなります。参照されるテーブルからDELETE
を期待する場合は、そのようなインデックスを作成してください。 TRUNCATE
にはインデックスは必要ありません。
不要なインデックスを作成しないでください。各インデックスにはメンテナンスコストがあります。インデックスの最小限のセットを使用し、ビットマップインデックススキャンでそれらを組み合わせて、巨大で高価なマルチカラムインデックスを多数維持するのではなく、それらを組み合わせてみてください。インデックスが必要な場合は、最初にテーブルを作成してから、最後にインデックスを作成してください。
データベース全体を保持するのに十分なRAMがあると、データベースを管理できれば大きなメリットになります。
十分なRAMがない場合は、ストレージが高速になるほど良くなります。安価なSSDでさえ、Rustの回転に大きな違いをもたらします。しかし、安価なSSDを本番用に信頼しないでください。それらは多くの場合、クラッシュセーフではなく、データを破壊する可能性があります。
グレッグ・スミスの本 PostgreSQL 9.0 High Performance は、やや古いバージョンに言及しているにも関わらず、関連性があります。役立つリファレンスになるはずです。
PostgreSQLの一般的なメーリングリストに参加してフォローしてください。