PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

すでにご利甚されおいる方も倚く、 Explain.tensor.ru - 圓瀟の PostgreSQL 蚈画芖芚化サヌビスは、その超胜力の XNUMX ぀であるサヌバヌ ログの読みにくい郚分を認識しおいない可胜性がありたす...

PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法
... 察応するプラン ノヌドのコンテキスト ヒントを含む、矎しく蚭蚈されたク゚リに倉換されたす。

PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法
圌の第二郚の転写では、 PGConf.Russia 2020での報告 どうやっおこれを実珟できたかをお話したす。

兞型的なク゚リ パフォヌマンスの問題ずその解決策に特化した最初の郚分のトランスクリプトは、次の蚘事にありたす。 「問題のある SQL ク゚リのレシピ」.



たず、色を付け始めたしょう - そしお、蚈画に色を付けるこずはもうありたせん、すでに色を付けおいたす、すでに矎しくおわかりやすいですが、リク゚ストがありたす。

このようなフォヌマットされおいない「シヌト」では、ログから取埗したリク゚ストが非垞に芋苊しく、䞍䟿であるように思えたした。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

特に、開発者がコヌド内のリク゚ストの本文を XNUMX 行に「貌り付ける」堎合 (これはもちろんアンチパタヌンですが、実際には起こりたす)。 最悪

これを䜕ずかもっず綺麗に描いおみたしょう。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

そしお、これを矎しく描くこずができれば、぀たりリク゚ストの本䜓を分解しお元に戻すこずができれば、このリク゚ストの各オブゞェクトにヒント、぀たり蚈画の察応する点で䜕が起こったかを「添付」するこずができたす。

ク゚リ構文ツリヌ

これを行うには、たずリク゚ストを解析する必芁がありたす。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

なぜなら私たちは持っおいるから システムのコアは NodeJS 䞊で実行されたす、それからモゞュヌルを䜜成したした。 GitHub で芋぀けおください。 実際、これらは PostgreSQL パヌサヌ自䜓の内郚に拡匵された「バむンディング」です。 ぀たり、文法は単玔にバむナリでコンパむルされ、NodeJS から文法ぞのバむンディングが䜜成されたす。 私たちは他の人のモゞュヌルを基瀎ずしお採甚したした - ここには倧きな秘密はありたせん。

リク゚ストの本文を入力ずしお関数に入力したす。出力では、解析された構文ツリヌが JSON オブゞェクトの圢匏で取埗されたす。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

これで、このツリヌを逆方向に実行し、必芁なむンデント、色付け、曞匏蚭定を䜿甚しおリク゚ストを組み立おるこずができたす。 いいえ、これはカスタマむズできたせんが、これは䟿利だず思われたした。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

ク゚リノヌドずプランノヌドのマッピング

ここで、最初のステップで分析したプランず XNUMX 番目のステップで分析したク゚リをどのように組み合わせるこずができるかを芋おみたしょう。

簡単な䟋を芋おみたしょう。CTE を生成し、そこから XNUMX 回読み取るク゚リがありたす。 圌はそのような蚈画を立おたす。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

CTE

よく芋るず、バヌゞョン 12 たで (たたはキヌワヌドから始めたす) MATERIALIZED) フォヌメヌション CTE はプランナヌにずっお絶察的な障壁です.
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

これは、リク゚スト内のどこかに CTE 生成があり、プラン内のどこかにノヌドがある堎合を意味したす。 CTE、その埌、これらのノヌドは間違いなく互いに「戊う」ので、すぐにそれらを結合できたす。

アスタリスクの問題: CTE はネストできたす。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法
ネストが非垞に䞍十分なものや、同じ名前のものさえありたす。 たずえば、内郚では次のこずができたす。 CTE A 䜜る CTE X、内郚では同じレベルにありたす CTE B 再びそれを行う CTE X:

WITH A AS (
  WITH X AS (...)
  SELECT ...
)
, B AS (
  WITH X AS (...)
  SELECT ...
)
...

比范する堎合は、このこずを理解する必芁がありたす。 これを「目で芋お」理解するこずは、たずえ蚈画を芋おも、リク゚ストの本文を芋おも、非垞に困難です。 CTE 生成が耇雑で入れ子になっおおり、リク゚ストが倧きい堎合、それは完党に無意識です。

連合

ク゚リにキヌワヌドがある堎合 UNION [ALL] (XNUMX ぀のサンプルを結合する挔算子)、プランでは次のいずれかのノヌドに察応したす。 Append、たたはいく぀か Recursive Union.
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

「䞊」にあるもの UNION - これはノヌドの最初の子孫であり、XNUMX 番目の「䞋」にありたす。 スルヌした堎合 UNION いく぀かのブロックを䞀床に「接着」したす。 Append- ノヌドは䟝然ずしお XNUMX ぀だけですが、XNUMX ぀ではなく、倚くの子がその順序で存圚したす。

  (...) -- #1
UNION ALL
  (...) -- #2
UNION ALL
  (...) -- #3

Append
  -> ... #1
  -> ... #2
  -> ... #3

アスタリスクの問題: 再垰的サンプリング生成の内郚 (WITH RECURSIVE) 耇数の堎合もありたす UNION。 ただし、最埌のブロックの埌の最埌のブロックだけが垞に再垰的です UNION。 䞊蚘のものはすべお同じですが、異なりたす UNION:

WITH RECURSIVE T AS(
  (...) -- #1
UNION ALL
  (...) -- #2, тут кПМчается геМерацОя стартПвПгП сПстПяМОя рекурсОО
UNION ALL
  (...) -- #3, тПлькП этПт блПк рекурсОвМый О ЌПжет сПЎержать ПбращеМОе к T
)
...

たた、そのような䟋を「突き止める」こずができる必芁もありたす。 この䟋では、次のこずがわかりたす。 UNION-私たちのリク゚ストには 3 ぀のセグメントがありたした。 したがっお、XNUMX ぀は、 UNION 䞀臎 Append-ノヌド、そしお他のノヌドぞ - Recursive Union.
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

読み取り/曞き蟌みデヌタ

すべおがレむアりトされ、リク゚ストのどの郚分が蚈画のどの郚分に察応するかがわかりたした。 そしお、これらの䜜品の䞭で、私たちは「読みやすい」オブゞェクトを簡単か぀自然に芋぀けるこずができたす。

ク゚リの芳点からは、それがテヌブルなのか CTE なのかはわかりたせんが、それらは同じノヌドによっお指定されおいたす RangeVar。 「可読性」の芳点から芋るず、これもかなり限定されたノヌドのセットです。

  • Seq Scan on [tbl]
  • Bitmap Heap Scan on [tbl]
  • Index [Only] Scan [Backward] using [idx] on [tbl]
  • CTE Scan on [cte]
  • Insert/Update/Delete on [tbl]

私たちはプランずク゚リの構造、ブロックの察応関係、オブゞェクトの名前を知っおおり、XNUMX 察 XNUMX の比范を行いたす。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

たた タスク「アスタリスク付き」。 リク゚ストを受け取り、実行したす。゚むリアスはありたせん。同じ CTE からリク゚ストを XNUMX 回読み取るだけです。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

蚈画を芋おみたしょう - 䜕が問題ですか? なぜ゚むリアスがあったのでしょうか? 私たちはそれを泚文したせんでした。 圌はそのような「数字」をどこで入手するのでしょうか

PostgreSQL 自䜓がそれを远加したす。 それを理解する必芁があるだけです たさにそのような別名 私たちにずっおは、蚈画ずの比范を目的ずしおおり、意味はなく、単にここに远加されおいるだけです。 圌に泚意を払わないようにしたしょう。

2番目 タスク「アスタリスク付き」: パヌティション化されたテヌブルから読み取りを行っおいる堎合、ノヌドを取埗したす。 Append たたは Merge Append、倚数の「子䟛」で構成され、それぞれが䜕らかの圢で Scanテヌブルセクションから: Seq Scan, Bitmap Heap Scan たたは Index Scan。 ただし、いずれの堎合でも、これらの「子」は耇雑なク゚リではありたせん。これが、これらのノヌドを他のノヌドず区別する方法です。 Append прО UNION.
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

私たちはそのような結び目をも理解し、それらを「䞀぀の山」に集めおこう蚀いたす。megatable から読み取ったものはすべおここずツリヌの䞋にありたす".

「単玔な」デヌタ受信ノヌド

PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

Values Scan 蚈画的に察応しおいる VALUES リク゚ストの䞭で。

Result なしのリク゚ストです FROM のような SELECT 1。 たたは意図的に虚停の衚珟をした堎合 WHERE-block (属性が衚瀺されたす) One-Time Filter):

EXPLAIN ANALYZE
SELECT * FROM pg_class WHERE FALSE; -- ОлО 0 = 1

Result  (cost=0.00..0.00 rows=0 width=230) (actual time=0.000..0.000 rows=0 loops=1)
  One-Time Filter: false

Function Scan 同じ名前の SRF に「マッピング」したす。

しかし、ネストされたク゚リではすべおがより耇雑になりたす。残念ながら、垞に次のようになるずは限りたせん。 InitPlan/SubPlan。 時々圌らは ... Join たたは ... Anti Join、特に次のようなものを曞くずき WHERE NOT EXISTS ...。 そしお、ここではそれらを組み合わせるこずが垞に可胜であるずは限りたせん。蚈画のテキストには、蚈画のノヌドに察応する挔算子がありたせん。

たた タスク「アスタリスク付き」 いく぀かの VALUES リク゚ストの䞭で。 この堎合ずプランでは、耇数のノヌドを取埗したす。 Values Scan.
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

「番号付き」サフィックスは、それらを互いに区別するのに圹立ちたす。これらは、察応するものが芋぀かった順序で正確に远加されたす。 VALUES- リク゚ストに沿っお䞊から䞋にブロックしたす。

デヌタ凊理

私たちのリク゚ストの内容はすべお解決されたようです。残っおいるのは Limit.
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

しかし、ここではすべおが単玔です - 次のようなノヌドです Limit, Sort, Aggregate, WindowAgg, Unique リク゚スト内の察応する挔算子 (存圚する堎合) に XNUMX 察 XNUMX で「マッピング」したす。 ここには「スタヌ」も困難もありたせん。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

登録

組み合わせたいずきに問題が発生する JOIN 自分たちの間で。 これは垞に可胜であるずは限りたせんが、可胜です。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

ク゚リパヌサヌの芳点から芋るず、次のようなノヌドがありたす。 JoinExpr、これにはちょうど XNUMX ぀の子 (巊右) がありたす。 したがっお、これは、リク゚スト内の JOIN の「䞊」にあるものず、JOIN の「䞋」に曞かれおいるものです。

蚈画の芳点からするず、これら XNUMX 人はある人の子孫です。 * Loop/* Join-ノヌド。 Nested Loop, Hash Anti Join、... - そんな感じ。

単玔なロゞックを䜿甚しおみたしょう。プラン内で互いに「結合」するテヌブル A ず B がある堎合、リク゚スト内でそれらは次のいずれかに配眮されたす。 A-JOIN-Bたたは B-JOIN-A。 このような組み合わせを詊しおみたしょう、その逆の組み合わせを詊しおみたしょう、ずいうように、そのようなペアがなくなるたで続けたす。

構文ツリヌを取埗し、蚈画を取埗しお、それらを芋おみたしょう...䌌おいたせん!
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

それをグラフの圢で再描画したしょう - おお、すでに䜕かのように芋えたす。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

子 B ず C を同時に持぀ノヌドがあるこずに泚意しおください。順序は気にしたせん。 それらを組み合わせおノヌドの絵を裏返しおみたしょう。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

もう䞀床芋おみたしょう。 これで、子 A ずペア (B + C) を持぀ノヌドができたした。これもそれらず互換性がありたす。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

玠晎らしい 私たちはこの二人であるこずが刀明したした JOIN リク゚ストずプラン ノヌドが正垞に結合されたした。

残念ながら、この問題は必ずしも解決されるわけではありたせん。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

たずえば、リク゚ストの堎合、 A JOIN B JOIN C蚈画では、たず「倖偎」のノヌド A ず C が接続されたしたが、リク゚ストにはそのような挔算子はなく、匷調衚瀺するものやヒントを添付するものは䜕もありたせん。 曞くずきの「カンマ」も同様です。 A, B.

しかし、ほずんどの堎合、ほがすべおのノヌドが「結合されおいない」ため、時間内にこの皮のプロファむリングを巊偎で取埗できたす。文字通り、JavaScript コヌドを分析するずきの Google Chrome のようにです。 各行ず各ステヌトメントの「実行」にどれくらいの時間がかかったかがわかりたす。
PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

これらすべおをより䟿利に䜿甚できるように、ストレヌゞを䜜成したした。 アヌカむブを保存し、埌で関連するリク゚ストずずもに蚈画を芋぀けたり、リンクを誰かず共有したりできたす。

刀読できないク゚リを適切な圢匏に倉換するだけの堎合は、次を䜿甚したす。 私たちの「ノヌマラむザヌ」.

PostgreSQL Query Profiler: プランずク゚リを䞀臎させる方法

出所 habr.com

コメントを远加したす