web-dev-qa-db-ja.com

PostgreSQL:データをメモリに強制します

PostgreSQLに特定のテーブルをメモリにロードさせる、または少なくともディスクから読み取ってシステムでキャッシュされるようにするための体系的な方法はありますか?

34
Adam Matan

メーリングリストのトピック の1つに関心があるかもしれません。TomLane(コア開発者)が回答します。

[..]しかし、私の意見では、LRUキャッシングアルゴリズムよりも賢いと思っている人は、一般的に誤解されています。テーブルの使用頻度が高い場合は、メモリ内に問題なく保持されます。 LRUアルゴリズムに従ってメモリ内にとどまるのに十分に使用されていない場合、メモリスペースは実際に他の何かに費やされるべきです。 [..]

また、SO質問: https://stackoverflow.com/questions/486154/postgresql-temporary-tables に関心があり、より適切な場合もあります https://stackoverflow.com/questions/407006/need-to-load-the-whole-postgresql-database-into-the-ram

27
DrColossos

Postgres 9.4は、最後に、関係からOSまたはデータベースバッファキャッシュ(選択)にデータをプリロードする拡張機能を追加しました。

pg_prewarm

これにより、より迅速に完全な動作パフォーマンスに到達できます。

データベースで1回実行します(詳細な手順 ここ ):

CREATE EXTENSION pg_prewarm;

次に、任意の関係をプリロードするのは簡単です。基本的な例:

SELECT pg_prewarm('my_tbl');

検索パスでmy_tblという名前の最初のテーブルを見つけ、それをPostgresバッファキャッシュにロードします

または:

SELECT pg_prewarm('my_schema.my_tbl', 'prefetch');

prefetchは、サポートされている場合、オペレーティングシステムに非同期プリフェッチ要求を発行します。サポートされていない場合は、エラーをスローします。 readは、要求された範囲のブロックを読み取ります。 prefetchとは異なり、これは同期的であり、すべてのプラットフォームとビルドでサポートされていますが、遅くなる可能性があります。 bufferは、要求された範囲のブロックをデータベースバッファーキャッシュに読み込みます。

デフォルトはbufferであり、これは最大の影響(高コスト、最高の効果)をもたらします。

詳細はマニュアルを読んでください 、引用はそこからです。
Depesz blogged それについても。

39

一般的なケースでは、十分なRAMがある場合、通常はデータベースサービスを信頼して、RAMで定期的に使用するものを適切に保持することができます。システムによっては、テーブルが常にRAMに保持されます(これは、頻繁に使用されない小さいテーブルに役立ちますが、使用されるときは、できるだけ迅速に応答することが重要です)。ただし、pgsqlにそのようなテーブルヒントがある場合アプリケーション全体の速度が低下する可能性があるため、他のキャッシュに使用できるメモリの量を減らしているので、これらの使用には十分注意する必要があります。

起動時にデータベースのページキャッシュを準備する場合(たとえば、再起動や、DBにキャッシュされているすべての情報を失わせる他のメンテナンス操作の後)、次のスクリプトを記述します。

SELECT * FROM <table>
SELECT <primary key fields> FROM <table> ORDER BY <primary key fields>
SELECT <indexed fields> FROM <table> ORDER BY <indexed fields>

(その最後のステップは、各インデックスまたはコースに対して繰り返され、ORDER BY句のフィールドが正しい順序になるように注意してください)

上記を実行すると、すべてのデータとインデックスページが読み込まれ、RAMページキャッシュ(少なくとも当面の間)に読み込まれます。アプリケーションデータベース用にこのようなスクリプトがあります。これらは再起動後に実行されるため、後でシステムにログインした最初のユーザーの応答が遅くなることはありません。このようなスクリプトは、db定義テーブル(MSSQLのsys.objects/sys.indexes/sys.columnsなど)をスキャンするのではなく、手書きで作成することをお勧めします。次に、スキャンに時間がかかるすべてをスキャンするのではなく、最もよく使用されるインデックスを選択的にスキャンできます。

4
David Spillett

私は同様の問題がありました:
サーバーサービスを再起動し、キャッシュされたすべてのデータを削除した後、多くのクエリが初めて呼び出され、本当に遅く、必要なすべてのインデックスとデータがキャッシュされるまで、クエリの特定の複雑さの原因となりました。つまり、たとえば、ユーザーは「アイテム」ごとに1回(実行時間1〜3秒)、5000万行の関連データをヒットする必要があるため、ユーザーは不要な遅延を経験しなくなります。ほとんどの使用データがキャッシュされ、プログラムが本番稼働のパフォーマンスで一流を台無しにするまで、ユーザーが煩わしいハングを経験するまでに最初の3時間かかります。それでも、2日間の突然の短い遅延が発生し、初めてアクセスするデータが少ない場合... 、統計データなど.

これを解決するために、大きなインデックスを持つ最も使用頻度の高いテーブルで選択を実行する小さなpythonスクリプトを記述しました。実行に15分かかり、パフォーマンスの遅延はありませんでした。

1
LongBeard_Boldy

私は RamDrive をQSoftから使用しました。これは benchmarked でしたが、Windowsの最速のramdiskとして使用されました。使ったばかり

initdb -D e:\data

ここで、e:\はRamDiskの場所です。

0
David

うーん、COPYコマンドが役立つかもしれません。 COPYをstdoutに実行し、そこから読み取ります。 pg_dumpを使用してそれを行うことが可能です:

pg_dump -U <user> -t <table> <database> > /dev/null

他の方法は、すべてのテーブルファイルを見つけてcat <files> > /dev/nullを実行することです。

テーブルファイル名を取得する方法の例を次に示します。

# SELECT oid, datname FROM pg_database ;
  oid  |  datname  
-------+-----------                                                                                                                                          
<...>
 16384 | test
-- out of database is 16384
# SELECT oid, relname FROM pg_class WHERE relname like 'fn%';
  oid  | relname 
-------+---------
 24576 | fn
(1 row)
-- oid of our table is 24576

したがって、テーブルのファイルは/ path/to/pgsql/data/base/16384/24576 *です。

同様に、インデックスとトーストテーブルも読み取り、それらのOIDを取得する必要があります。

ところで、なぜあなたはそれが必要なのですか? postgresqlとOSは、最もホットなデータをキャッシュし、適切に維持するのに十分スマートだと思います。キャッシュ効率。

0
rvs