HN 日本語サマリー

← 一覧へ戻る
プログラミング

random_page_costに関するさらなる考察

Some more thoughts on random_page_cost (vondra.me)

17 pointsby blueshoess1 コメント

要約

PostgreSQLの`random_page_cost`パラメータは、ストレージのランダムI/Oコストをモデル化しますが、SSDの普及によりそのデフォルト値(4.0)が実情に合わなくなっています。著者は、`random_page_cost`が単なるI/Oコストではなく、メモリ使用量、キャッシュ効果、アクティブセットの局所性といった、コストモデルが捉えきれていない他の要因を補償する役割を果たしていると考察しています。そのため、このパラメータの調整はシステム固有であり、プロファイリング結果だけでなく、実際のクエリパフォーマンスの監視に基づいて行う必要があると結論付けています。

全文翻訳

random_page_cost に関するさらなる考察

数ヶ月前、私は現在のストレージがランダムアクセスとシーケンシャルアクセスをどのように処理するかをより良く反映するために random_page_cost を調整することについて投稿しました。それ以来、このトピックについて多くの素晴らしい議論がありましたが、最終的には他のことに気を取られてしまいました。

先週、POSETTE が開催され、このトピックに関する私の事前録画された講演(素晴らしい講演がたくさんありました)が行われました。それを機に、random_page_cost について少し違う見方をし始めたことを思い出しました。そこで、さらなる考察を加えて更新します。

以前の投稿やPOSETTEでの講演で、これらの点の一部に触れました。

それに入る前に、回転式SATAドライブでの random_page_cost の結果を示すグラフを共有します。メンテナンスのためにケースを開けるまで、これらのディスクをマシンに入れていることを完全に忘れていました。これらは、約2000年頃の元の実験で使用されたストレージに近いでしょう。おそらくPATAまたはSCSIドライブですが、それでも回転式です。もしかしたら、4.0のデフォルトに近い値が得られるかもしれません。

[画像: random_page_cost の結果を示すグラフ]

明らかにそうではありません。実際、推定 random_page_cost は約125で、SSDストレージの推定値の2〜4倍です。つまり、SSDではデフォルトに近づいていますが、それは偶然です。

おそらく、古い実験の基本的な部分で、私たちが思い出せなかった何かがあるのでしょうか?あるいは、「生の」結果がある程度調整されたのかもしれません。しかし、4.0のデフォルト値がランダムI/Oの「生の」コストではなかったようです。

過去に random_page_cost を増やそうとした人々から多くのフィードバックを得ました。彼らの経験では、パフォーマンスが向上することはなく、むしろ悪化しました。コスト計算の精度が低下するのに、これはどのようにして可能なのでしょうか?

私は、random_page_cost がコストモデルの不完全さを「補償」しているのだと考えています。これは、様々なキャッシュ効果や、多くのランダムI/Oを実行するプランに関連するリソースを考慮していません。

すべてのコストモデルは近似であり、比較的粗雑なものです。すべての詳細を正確に模倣する高速/低コストなコストモデルを持つことは不可能です。詳細を増やしていくことはできますが、ある時点で元のシステムと同じくらい大きくなってしまうでしょう。その場合、なぜモデルが必要なのでしょうか?それはほとんど役に立たないでしょう。

私たちのコストモデルには、ここで重要だと考えるいくつかのギャップがあります。

コストモデルは(ほとんど)メモリを無視する

操作のコストは、操作の実行に使用されるCPUとI/Oの量から計算されます。これらは2つの主要なリソースですが、メモリを無視しています。

  • もう1つの重要なリソースです。

work_mem はありますが、これは作業バッファ(例: ソートやハッシュ用)のサイズを制限する安全な制限値のようなものです。そして、操作が必要とするI/Oの量に影響を与える可能性があります(例: ハッシュ結合でバッファが小さいと、ディスクへのスピルが増える)。

しかし、プランが「使用」する他のメモリを追跡するわけではなく、メモリの他の用途を無視します。

100GBのテーブルがあり、その中に1GBの「興味深い」データ(クエリ述語に一致する)が含まれているとします。テーブルをシーケンシャルスキャンするか、インデックス経由でスキャンするかできます。テーブルが「コールド」の場合、シーケンシャルスキャンは他の約100GBのデータをメモリ(共有バッファまたはページキャッシュ)から追い出す可能性があります。クエリは work_mem=4MB で問題なく実行されるかもしれませんが、実質的に100GBのメモリを「使用」する可能性があります。

一方、インデックスはテーブルの約1%(興味深い1GBのデータ)しかアクセスしないかもしれません。ランダムI/Oはシーケンシャルスキャンよりも時間がかかる可能性がありますが、一方でメモリは1GBしか「使用」しません。キャッシュから追い出される他のデータははるかに少なくなります。

しかし、コストモデルはこれに全く気づいていません。

アクセスの局所性

もう1つの理由は、アクティブセットという概念です。1TBのデータベースがあるかもしれませんが、ほとんどの実用的なシステムでは、データのほんの一部しかアクセスされません。ユーザーは最新の注文などしか見ません。これが、データベースの「アクティブセット」と呼ばれるものです。

鍵は、アクティブセットをメモリ内に保持することです。そして、多くのランダムI/Oを実行するプランは、より局所化される傾向があります。つまり、「興味深い」データのみにアクセスします。インデックススキャンは、通常、シーケンシャルスキャンよりもはるかに少ないデータ量をアクセスします。I/Oはより高価になる可能性があります(ランダム、複数回ページを訪問する)が、それは「興味深い」データだけです。

シーケンシャルスキャンはアクティブセットを大幅に拡大する可能性があります - おそらくデータベース全体にまで。これは、実際にデータベース全体を収容するのに十分なRAMがない限り、あまり良くありません。インデックススキャンは、はるかに小さいアクティブセットを可能にします。

しかし、プランナーはアクティブセットを全く認識していません。すべてのクエリがコールドデータから始まると仮定してクエリを計画します。キャッシュ効果は非常に限定的な場合にのみ考慮されます。例えば、同じクエリ内でのキャッシュです。

プランナーは、他の多くのことにも気づいていません。他のクエリが同じリソースを競合しておらず、帯域幅が無限であるかのように、クエリを個別に計画します。シーケンシャルスキャンは単一のバックエンドには最適かもしれませんが、100個のバックエンドすべてがシーケンシャルスキャンを実行している場合、ストレージ帯域幅に達するでしょう。

結論

私は今、random_page_cost をこれらのすべての効果のプロキシとして見ています。

プランナーは、CPU/ディスクと同じようにメモリをコスト計算しておらず、キャッシュ効果も理解していません。より低い random_page_cost 値は、より局所的でアクティブセットを制御下に保つプランへと導きます。これは長期的には勝利戦略のように思えます。

これは、ストレージをプロファイリングしてシーケンシャルおよびランダムI/Oの処理方法を測定した後に、random_page_cost の「正しい」値を示せるツールは存在しないことを意味します。私はそれを望んでいますが、もし random_page_cost が生のI/Oコストでないなら、それは機能しないでしょう。

random_page_cost のチューニングは、監視からのフィードバックによって駆動される、システム固有のものでなければなりません。例えば、pg_stat_statements のトップクエリを見て、それらがより低い random_page_cost 値から恩恵を受けるかどうかを確認できます。次に、値を調整してみて、それが望ましい影響(または他のクエリを損なうかどうか)を与えるかを監視します。

この投稿についてフィードバックはありますか? tomas@vondra.me までメールでご連絡ください。