232

典型的な Rails アプリケーションの SQLite から PostgreSQL に切り替えています。

問題は、PG で動作スペックが遅くなったことです。
SQLite では約 34 秒、PG では約 76 秒かかり、2 倍以上遅くなります

そこで、コードを変更せずに仕様のパフォーマンスを SQLite と同等にするためのいくつかの手法を適用したいと考えています(理想的には、接続オプションを設定するだけですが、これはおそらく不可能です)。

私の頭の上から明らかなことのいくつかは次のとおりです。

  • RAM ディスク (OSX で RSpec を適切にセットアップするとよいでしょう)
  • ログに記録されていないテーブル (データベース全体に適用できるので、すべてのスクリプトを変更する必要はありませんか?)

ご存じかもしれませんが、私は信頼性やその他のことは気にしません (ここでは、DB はただの使い捨てです)。
PG を最大限に活用し、できるだけ速くする必要があります

最良の答えは、理想的には、それを行うためのトリック、セットアップ、およびそれらのトリックの欠点を説明することです.

更新: fsync = off +full_page_writes = off時間は ~65 秒 (~-16 秒) に短縮されました。スタートは良かったが、目標の 34 にはほど遠い。

更新 2: RAM ディスクを使用しようとしましたが、パフォーマンスの向上は誤差範囲内でした。なので割に合わないようです。

更新 3:* 最大のボトルネックを発見し、仕様が SQLite と同じくらい高速に動作するようになりました。

問題は、切り捨てを行ったデータベースのクリーンアップでした。どうやら SQLite は速すぎるようです。

それを「修正」するために、各テストの前にトランザクションを開き、最後にロールバックします。

〜700回のテストのいくつかの数値。

  • 切り捨て: SQLite - 34 秒、PG - 76 秒。
  • トランザクション: SQLite - 17 秒、PG - 18 秒。

SQLite の速度が 2 倍になりました。PGの速度が4倍になります。

4

2 に答える 2

311

まず、常に最新バージョンの PostgreSQL を使用してください。パフォーマンスの改善は常に行われているため、古いバージョンをチューニングしていると、おそらく時間を無駄にしていることになります。たとえば、PostgreSQL 9.2 では速度が大幅に向上し、TRUNCATEもちろんインデックス オンリー スキャンが追加されています。マイナー リリースであっても、常に従う必要があります。バージョン ポリシーを参照してください。

してはいけないこと

テーブルスペースを RAMdisk またはその他の非永続ストレージに置かないでください

テーブルスペースが失われると、データベース全体が破損し、大きな作業を行わないと使いにくくなる可能性があります。UNLOGGEDとにかくテーブルを使用し、キャッシュ用に大量の RAM を使用する場合と比較して、これにはほとんど利点がありません。

本当に RAM ディスク ベースのシステムが必要な場合は、RAM ディスク上に新しい PostgreSQL インスタンスを作成することinitdbで、RAM ディスク上にまったく新しいクラスターを作成しinitdbます。したがって、完全に使い捨ての PostgreSQL インスタンスが得られます。

PostgreSQL サーバー構成

テストするときは、耐久性はないが高速な操作のためにサーバーを構成できます。

fsync=offこれは、PostgreSQLで設定を使用できる唯一の使用方法の 1 つです。この設定は、PostgreSQL に、順序付けされた書き込みや、その他の厄介なデータ整合性保護やクラッシュ セーフ機能を気にしないように指示し、電源が失われたり OS がクラッシュした場合にデータを完全に破棄する許可を与えます。

言うまでもなくfsync=off、他の場所から再生成できるデータの一時データベースとして Pg を使用している場合を除き、本番環境では決して有効にしないでください。fsync をオフにしようとしている場合に限り、オフfull_page_writesにすることもできます。注意してクラスターレベルでfsync=off適用full_page_writesすると、PostgreSQL インスタンス内のすべてのデータベースに影響します。

本番環境で使用する場合は、 を使用synchronous_commit=offして設定することができます。これは、巨大なデータ破損のリスクがない場合commit_delayと同じ利点の多くが得られるためです。fsync=off非同期コミットを有効にすると、最近のデータがわずかに失われますが、それだけです。

DDL をわずかに変更するオプションがある場合はUNLOGGED、Pg 9.1+ のテーブルを使用して、WAL ロギングを完全に回避し、サーバーがクラッシュした場合にテーブルが消去されるという犠牲を払って実際の速度を向上させることもできます。すべてのテーブルをログに記録しないようにする構成オプションはありません。 で設定する必要がありますCREATE TABLE。これは、テストに適しているだけでなく、データベースに生成されたデータや重要でないデータでいっぱいのテーブルがあり、それ以外の場合は安全にする必要があるものを含んでいる場合に便利です。

ログをチェックして、チェックポイントが多すぎるという警告が表示されているかどうかを確認してください。そうであれば、checkpoint_segmentsを増やす必要があります。checkpoint_completion_target を調整して、書き込みをスムーズにすることもできます。

ワークshared_buffersロードに合わせて調整します。これは OS に依存し、マシンで他に何が起こっているかに依存し、試行錯誤が必要です。デフォルトは非常に保守的です。shared_buffersPostgreSQL 9.2 以下で増やす場合は、OS の最大共有メモリ制限を増やす必要がある場合があります。9.3 以降では、それを回避するために共有メモリの使用方法が変更されました。

多くの作業を行う接続を 2 つだけ使用している場合は、増やしwork_memて、並べ替えなどで使用できる RAM を増やします。設定が高すぎると、work_mem並べ替えごとではなく、メモリ不足の問題が発生する可能性があることに注意してください。接続ごとに、1 つのクエリに多数のネストされた並べ替えを含めることができます。実際に増やす必要work_memがあるのは、並べ替えがディスクに流出したり、設定EXPLAINでログに記録されたりする場合(推奨) だけですが、値を大きくすると、Pg がよりスマートなプランを選択できるようになります。log_temp_files

ここで別のポスターが言ったように、可能であれば、xlog とメインのテーブル/インデックスを別々の HDD に配置するのが賢明です。個別のパーティションはまったく無意味です。本当に個別のドライブが必要です。この分離は、テーブルfsync=offを使用している場合はほとんど利点がなく、実行している場合はほとんど利点がありません。UNLOGGED

最後に、クエリを調整します。random_page_costおよびseq_page_costがシステムのパフォーマンスを反映していることを確認し、正しいことを確認します。個々のクエリ プランを調べるためにeffective_cache_size使用し、モジュールをオンにしてすべての遅いクエリを報告します。多くの場合、適切なインデックスを作成するか、コスト パラメーターを微調整するだけで、クエリのパフォーマンスを大幅に向上させることができます。EXPLAIN (BUFFERS, ANALYZE)auto_explain

私の知る限り、データベース全体またはクラスター全体を として設定する方法はありませんUNLOGGED。それができたら面白いですね。PostgreSQL メーリング リストで質問することを検討してください。

ホスト OS のチューニング

オペレーティング システム レベルで実行できるチューニングもあります。あなたがしたいと思うかもしれない主なことは、オペレーティングシステムがディスクへの書き込みを積極的にフラッシュしないようにすることです。

Linux では、 のような仮想メモリ サブシステムdirty_*設定でこれを制御できますdirty_writeback_centisecs

ライトバック設定を緩く調整することの唯一の問題は、他のプログラムによるフラッシュにより、PostgreSQL の蓄積されたすべてのバッファもフラッシュされ、書き込み時にすべてがブロックされる間に大きなストールが発生する可能性があることです。別のファイル システムで PostgreSQL を実行することでこれを軽減できる場合がありますが、一部のフラッシュはファイル システム レベルではなくデバイス レベルまたはホスト全体レベルである可能性があるため、それに頼ることはできません。

この調整では、ワークロードに最適な設定を確認するために、設定をいじる必要があります。

新しいカーネルでは、vm.zone_reclaim_modePostgreSQL がshared_buffers.

クエリとワークロードの調整

これらはコードの変更を必要とするものです。彼らはあなたに合わないかもしれません。応用できるものもあります。

作業をより大きなトランザクションにバッチ処理していない場合は、開始してください。小規模なトランザクションの多くはコストがかかるため、可能で実用的な場合はいつでもバッチ処理を行う必要があります。非同期コミットを使用している場合、これはそれほど重要ではありませんが、強くお勧めします。

可能な限り、一時テーブルを使用してください。WAL トラフィックを生成しないため、挿入と更新がはるかに高速です。大量のデータを一時テーブルに丸呑みし、必要に応じて操作してから、 を実行INSERT INTO ... SELECT ...して最終テーブルにコピーする価値がある場合があります。一時テーブルはセッションごとであることに注意してください。セッションが終了するか、接続が失われると、一時テーブルはなくなり、他の接続はセッションの一時テーブルの内容を見ることができなくなります。

PostgreSQL 9.1 以降を使用している場合はUNLOGGED、セッション状態など、失われてもよいデータにテーブルを使用できます。これらは異なるセッション間で表示され、接続間で保持されます。サーバーが不正にシャットダウンすると切り捨てられるため、再作成できないものには使用できませんが、キャッシュ、具体化されたビュー、状態テーブルなどには最適です.

一般に、しないでくださいDELETE FROM blah;TRUNCATE TABLE blah;代わりに使用してください。テーブル内のすべての行をダンプしている場合は、はるかに高速です。可能であれば、1 回の呼び出しで多くのテーブルを切り捨てTRUNCATEます。TRUNCATESただし、小さなテーブルを何度も何度も作成する場合は注意が必要です。参照: Postgresql 切り捨て速度

外部キーにインデックスがない場合DELETE、それらの外部キーによって参照される主キーを含む s は恐ろしく遅くなります。DELETE参照されるテーブルから作成することが予想される場合は、必ずそのようなインデックスを作成してください。にはインデックスは必要ありませんTRUNCATE

必要のないインデックスを作成しないでください。各インデックスにはメンテナンス コストがかかります。最小限のインデックス セットを使用し、ビットマップ インデックス スキャンでそれらを組み合わせるようにしてください。インデックスが必要な場合は、最初にテーブルにデータを入力してから、最後にインデックスを作成してください。

ハードウェア

データベース全体を保持するのに十分な RAM を持つことは、それを管理できれば大きなメリットです。

十分な RAM がない場合は、より高速なストレージを取得できるほど優れています。安価な SSD でさえ、サビの回転に大きな違いをもたらします。ただし、生産用の安価な SSD を信頼しないでください。多くの場合、クラッシュセーフではなく、データを消費する可能性があります。

学ぶ

Greg Smith の本PostgreSQL 9.0 High Performanceは、やや古いバージョンについて言及しているにもかかわらず、依然として関連性があります。参考になるはずです。

PostgreSQL の一般的なメーリング リストに参加して、フォローしてください。

読む:

于 2012-02-23T05:57:55.443 に答える
10

別のディスクレイアウトを使用します。

  • $PGDATA用の別のディスク
  • $ PGDATA/pg_xlog用の別のディスク
  • temファイル用の異なるディスク(データベースごとに$ PGDATA / base // pgsql_tmp)(work_memに関する注記を参照)

postgresql.confの微調整:

  • shared_memory:使用可能なRAMの30%ですが、6〜8GB以下です。書き込みが集中するワークロードには、共有メモリを少なくする(2GB〜4GB)方がよいようです。
  • work_mem:主にsorts/aggregationsを使用したselectクエリ用。これは接続設定ごとであり、クエリはその値を複数回割り当てることができます。データが収まらない場合は、ディスクが使用されます(pgsql_tmp)。「explainanalyze」をチェックして、必要なメモリ量を確認してください
  • fsyncおよびsynchronous_commit:デフォルト値は安全ですが、失われたデータを許容できる場合は、オフにしてからオフにすることができます
  • random_page_cost:SSDまたは高速RAIDアレイを使用している場合は、これを2.0(RAID)に下げるか、SSDの場合はさらに低くする(1.1)ことができます。
  • checkpoint_segments:32または64を上に移動して、checkpoint_completion_targetを0.9に変更できます。値を小さくすると、クラッシュ後の回復が速くなります
于 2012-02-23T06:05:10.760 に答える