PostgreSQLは正確に私に言って何を説明していますか?


116

MySQLの説明出力は非常に簡単です。PostgreSQLはもう少し複雑です。それを説明する優れたリソースも見つかりませんでした。

説明が正確に言っていることを説明できますか、または少なくとも私を良いリソースの方向に向けることができますか?

回答:


50

Explaining_EXPLAIN.pdfも役立ちます。


64
スライドデッキが優れた技術文書を作成する理由を人々が考える理由に私は不思議に思います。講演のビデオは役に立つかもしれませんが、そのスライドデッキの情報密度はゼロに非常に近いです。最初の6枚のスライド(全体の1/5)には、技術的な内容が1文だけ含まれています。私の最大の誤解は、「起動」時間が何を意味するかであり、それはこれらの30枚までのスライドのどこにも説明されていません。
Mark E. Haase、2016

80

私がいつも混乱しているのは、初期コストと総コストです。私はそれを忘れるたびにこれをグーグルします、それは私をここに戻します、それは違いを説明しません、それが私がこの答えを書いている理由です。これは私がPostgresのEXPLAINドキュメントから収集したものであり、私が理解しているときに説明されています。

フォーラムを管理するアプリケーションの例を次に示します。

EXPLAIN SELECT * FROM post LIMIT 50;

Limit  (cost=0.00..3.39 rows=50 width=422)
  ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

PgAdminからのグラフィカルな説明は次のとおりです。

最初のクエリのグラフィカルな説明

(PgAdminを使用している場合は、コンポーネントにマウスを合わせると、コストの詳細が表示されます。)

コストはタプルとして表されます。たとえば、LIMITis cost=0.00..3.39のコストと順次スキャンのコストpostcost=0.00..15629.12です。タプルの最初の数値は初期費用で、2番目の数値は総費用です。私は使用EXPLAINしていたのでEXPLAIN ANALYZE、これらのコストは実際の測定値ではなく推定値です。

  • スタートアップコストはトリッキーなコンセプトです。コンポーネントが開始するまでの時間を表すだけではありません。これは、コンポーネントが実行(データの読み取り)を開始してから、コンポーネントが最初の行を出力するまでの時間を表します。
  • 総コストは、コンポーネントがデータの読み取りを開始してから出力の書き込みを完了するまでの、コンポーネントの実行時間全体です。

厄介なことに、各「親」ノードのコストには、その子ノードのコストが含まれます。テキスト表現では、ツリーはインデントで表されLIMITますSeq Scan。たとえば、親ノードであり、その子です。PgAdmin表現では、矢印は子から親(データフローの方向)を指しています。これは、グラフ理論に精通している場合は直観に反する可能性があります。

ドキュメントには、コストにはすべての子ノードが含まれていると記載されていますが、親3.39の合計コストはその子の合計コストよりもはるかに小さいことに注意して15629.12ください。のようなコンポーネントLIMITは入力全体を処理する必要がないため、総コストは包括的ではありません。PostgresのドキュメントEXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2;例を参照してください。EXPLAIN

上記の例では、どちらのコンポーネントも行の書き込みを開始する前に処理を行う必要がないため、両方のコンポーネントの起動時間はゼロです。シーケンシャルスキャンはテーブルの最初の行を読み取って出力します。LIMITその最初の行を読み取り、それを放出します。

コンポーネントが行の出力を開始する前に、多くの処理を行う必要があるのはいつですか?考えられる理由はたくさんありますが、1つの明確な例を見てみましょう。これは前と同じクエリですが、現在はORDER BY句が含まれています。

EXPLAIN SELECT * FROM post ORDER BY body LIMIT 50;

Limit  (cost=23283.24..23283.37 rows=50 width=422)
  ->  Sort  (cost=23283.24..23859.27 rows=230412 width=422)
        Sort Key: body
        ->  Seq Scan on post  (cost=0.00..15629.12 rows=230412 width=422)

そしてグラフィカルに:

2番目のクエリのグラフィカルな説明

繰り返しになりますが、順次スキャンpostの開始コストはありません。行の出力がすぐに開始されます。ただし、1行でも出力する前にテーブル全体23283.24ソートする必要があるため、ソートの開始にはかなりのコストがかかります。並べ替えの合計コストは、23859.27開始コストよりもわずかに高くなります。これは、データセット全体が並べ替えられると、並べ替えられたデータが非常に迅速に出力されるという事実を反映しています。

お知らせの起動時間は、というLIMIT 23283.24一種の起動時間に正確に等しいです。これはLIMIT、起動時間が長いためではありません。起動時間自体は実際にはゼロですがEXPLAIN、各親のすべての子コストをロールアップするため、LIMIT起動時間にはその子の合計起動時間が含まれます。

このコストのロールアップは、個々のコンポーネントの実行コストを理解することを困難にする可能性があります。たとえば、私たちのLIMIT起動時間はゼロですが、一見するとそれは明らかではありません。そのため、Hubert Lubaczewski(別名depesz)によって作成されたツールであるExplain.depesz.comにリンクしている他の人々もいます。これは、とりわけEXPLAIN親コストから子コストを差し引くことによって理解するのに役立ちます。彼は自分のツールに関する短いブログ投稿で他のいくつかの複雑さについて言及しています。


4
これありがとう。また、出力(imo)を表示するためのより良い仕事をする説明ビジュアライザーを追加したいと思います。tatiyants.com/pev
ジョナサンポーター

すばらしい答えです。また、開始コストに最初の行が返されるまでの時間が含まれているというコメントは、Sortの開始コストが15629.12だけではなかった理由を理解するの役立ちました。
ジョエルウィグトン

43

最もインデントされたものから最もインデントされていないものまで実行され、計画の下部から上部へと信じています。(したがって、インデントされたセクションが2つある場合、ページの下の方が最初に実行され、次に他のセクションが実行されると、それらを結合するルールが実行されます。

アイデアは、各ステップで1つまたは2つのデータセットが到着し、いくつかのルールによって処理されるというものです。データセットが1つだけの場合、その操作はそのデータセットに対して行われます。(たとえば、インデックスをスキャンして、必要な行を特定するか、データセットをフィルター処理するか、または並べ替えます。)2つの場合、2つのデータセットはさらにインデントされた2つのものであり、それらは表示されるルールによって結合されます。ほとんどのルールの意味はかなり簡単に推測できます(特に、以前に一連の説明プランを読んだことがある場合)。ただし、ドキュメントを調べるか、または(簡単に)フレーズを入力するだけで、個々の項目を確認できます。のようないくつかのキーワードと一緒にグーグルEXPLAIN

これは明らかに完全な説明ではありませんが、通常は必要なことを何でも理解できる十分なコンテキストを提供します。たとえば、実際のデータベースからこの計画を検討してください:

explain analyze
select a.attributeid, a.attributevalue, b.productid
from orderitemattribute a, orderitem b
where a.orderid = b.orderid
and a.attributeid = 'display-album'
and b.productid = 'ModernBook';

------------------------------------------------------------------------------------------------------------------------------------------------------------

 Merge Join  (cost=125379.14..125775.12 rows=3311 width=29) (actual time=841.478..841.478 rows=0 loops=1)
   Merge Cond: (a.orderid = b.orderid)
   ->  Sort  (cost=109737.32..109881.89 rows=57828 width=23) (actual time=736.163..774.475 rows=16815 loops=1)
         Sort Key: a.orderid
         Sort Method:  quicksort  Memory: 1695kB
         ->  Bitmap Heap Scan on orderitemattribute a  (cost=1286.88..105163.27 rows=57828 width=23) (actual time=41.536..612.731 rows=16815 loops=1)
               Recheck Cond: ((attributeid)::text = 'display-album'::text)
               ->  Bitmap Index Scan on (cost=0.00..1272.43 rows=57828 width=0) (actual time=25.033..25.033 rows=16815 loops=1)
                     Index Cond: ((attributeid)::text = 'display-album'::text)
   ->  Sort  (cost=15641.81..15678.73 rows=14769 width=14) (actual time=14.471..16.898 rows=1109 loops=1)
         Sort Key: b.orderid
         Sort Method:  quicksort  Memory: 76kB
         ->  Bitmap Heap Scan on orderitem b  (cost=310.96..14619.03 rows=14769 width=14) (actual time=1.865..8.480 rows=1114 loops=1)
               Recheck Cond: ((productid)::text = 'ModernBook'::text)
               ->  Bitmap Index Scan on id_orderitem_productid  (cost=0.00..307.27 rows=14769 width=0) (actual time=1.431..1.431 rows=1114 loops=1)
                     Index Cond: ((productid)::text = 'ModernBook'::text)
 Total runtime: 842.134 ms
(17 rows)

自分で読んでみて、意味があるかどうかを確認してください。

私が読んだのは、データベースが最初にid_orderitem_productidインデックスをスキャンし、それを使用して必要な行を見つけorderitem、次にクイックソートを使用してそのデータセットをソートし(データがRAMに収まらない場合は使用されるソートが変更されます)、それを脇に置きます。

次に、スキャンしてorditematt_attributeid_idx目的の行を見つけ、orderitemattributeクイックソートを使用してそのデータセットをソートします。

次に、2つのデータセットを受け取り、それらをマージします。(マージ結合は、並べ替えられた2つのデータセットを並列にウォークし、一致したときに結合された行を出力する、一種の「圧縮」操作です。)

私が言ったように、あなたは計画の内側から外側へ、下から上へと作業します。



13

PgAdminは、説明計画のグラフィック表現を表示します。2つの間で切り替えを切り替えると、テキスト表現の意味を理解するのに役立ちます。ただし、それが何をするのかを知りたいだけの場合は、常にGUIを使用できる場合があります。



0

pgadminをインストールすると、[説明]ボタンが表示され、テキスト出力に何が起こっているのかを示す図が表示され、フィルター、並べ替え、サブセットマージが表示され、何が起こっているのかを確認するのに非常に役立ちます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.