䞍可解なこずを説明する。 パヌト3

PG Day'16カンファレンスの準備ずしお、PostgreSQLの興味深い偎面を玹介し続けたす。 そしお本日、Explainシリヌズの3番目の蚘事の翻蚳を提䟛したす。



このシリヌズの以前の 投皿では、Explain分析の出力の1行を解釈する方法ずその構造に぀いお曞き、デヌタExplainツリヌのノヌドを取埗するための基本操䜜に぀いおも説明したした。



今日は、より耇雑な操䜜に進みたす。







機胜スキャン



䟋



$ explain analyze select * from generate_Series(1,10) i; QUERY PLAN --------------------------------------------------------------------------------------------------------------------- Function Scan on generate_series i (cost=0.00..10.00 rows=1000 width=4) (actual time=0.012..0.013 rows=10 loops=1) Total runtime: 0.034 ms (2 rows)
      
      





抂しお、それは非垞に単玔なので、䜕かを説明する必芁は特にありたせん。 しかし、この操䜜は次の䟋で䜿甚されるため、少し説明したす。



関数スキャンは非垞に単玔なアセンブリです。 レコヌドセットを返す関数を実行し、それだけです。 「lower」のような関数は実行したせんが、倚くの行たたは列を返す可胜性がある関数のみを実行したす。関数が行を返すず、それらはプランツリヌのFunction Scanより1レベル高いノヌドたたはクラむアントに転送されたすFunction Scanがルヌトノヌドの堎合。



ここで発生する可胜性がある唯䞀の远加ロゞックは、次のように、受信した回線をフィルタリングする機胜です。



 $ explain analyze select * from generate_Series(1,10) i where i < 3; QUERY PLAN ------------------------------------------------------------------------------------------------------------------- Function Scan on generate_series i (cost=0.00..12.50 rows=333 width=4) (actual time=0.012..0.014 rows=2 loops=1) Filter: (i < 3) Rows Removed by Filter: 8 Total runtime: 0.030 ms (4 rows)
      
      





䞊べ替え



これは非垞に理解しやすいず思いたす-゜ヌトは遞択したレコヌドを取埗し、特定の方法で゜ヌトしお返したす。



䟋



 $ explain analyze select * from pg_class order by relname; QUERY PLAN --------------------------------------------------------------------------------------------------------------- Sort (cost=22.88..23.61 rows=292 width=203) (actual time=0.230..0.253 rows=295 loops=1) Sort Key: relname Sort Method: quicksort Memory: 103kB -> Seq Scan on pg_class (cost=0.00..10.92 rows=292 width=203) (actual time=0.007..0.048 rows=295 loops=1) Total runtime: 0.326 ms (5 rows)
      
      





簡単ですが、興味深いロゞックが朜んでいたす。 たず、゜ヌトに必芁なメモリがwork_memの倀よりも倧きい堎合、ディスク゜ヌトぞの切り替えが発生したす。



 $ explain analyze select random() as x from generate_series(1,14000) i order by x; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ Sort (cost=62.33..64.83 rows=1000 width=0) (actual time=16.713..18.090 rows=14000 loops=1) Sort Key: (random()) Sort Method: quicksort Memory: 998kB -> Function Scan on generate_series i (cost=0.00..12.50 rows=1000 width=0) (actual time=2.036..4.533 rows=14000 loops=1) Total runtime: 18.942 ms (5 rows) $ explain analyze select random() as x from generate_series(1,15000) i order by x; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ Sort (cost=62.33..64.83 rows=1000 width=0) (actual time=27.052..28.780 rows=15000 loops=1) Sort Key: (random()) Sort Method: external merge Disk: 264kB -> Function Scan on generate_series i (cost=0.00..12.50 rows=1000 width=0) (actual time=2.171..4.894 rows=15000 loops=1) Total runtime: 29.767 ms (5 rows)
      
      





䞊蚘の䟋の゜ヌト方法の倉曎に泚目しおください。



そのような堎合、Postgresは$ PGDATA / base / pgsql_tmp /ディレクトリに保存されおいる䞀時ファむルを䜿甚したす。 もちろん、それらの必芁性がなくなるずすぐに削陀されたす。



別の远加のプロパティは、次のように、Limit操䜜によっお呌び出された堎合、Sortが䜜業メ゜ッドを倉曎できるこずです。



 $ explain analyze select * from pg_class order by relfilenode limit 5; QUERY PLAN --------------------------------------------------------------------------------------------------------------------- Limit (cost=15.77..15.78 rows=5 width=203) (actual time=0.119..0.120 rows=5 loops=1) -> Sort (cost=15.77..16.50 rows=292 width=203) (actual time=0.118..0.118 rows=5 loops=1) Sort Key: relfilenode Sort Method: top-N heapsort Memory: 26kB -> Seq Scan on pg_class (cost=0.00..10.92 rows=292 width=203) (actual time=0.005..0.047 rows=295 loops=1) Total runtime: 0.161 ms (6 rows)
      
      





通垞、遞択したデヌタセットを䞊べ替えるには、デヌタセット党䜓を凊理する必芁がありたす。 しかし、Postgresは、必芁な行数が少ない堎合、デヌタセット党䜓を䞊べ替える必芁はなく、最初の倀のみを取埗すれば十分であるこずを知っおいたす。



Big O衚蚘では、䞀般的な䞊べ替えには耇雑床Om * logmがありたすが、Top-Nには耇雑床Om * lognがありたす。ここで、mはテヌブル内の行数、nは返される行数です。 この䞊べ替え方法は、䜿甚するメモリがはるかに少ないこずを知っおおくこずが重芁です最終的に、䞊べ替えられた行からデヌタセット党䜓を収集する必芁はなく、数行あれば十分です。したがっお、䞀時ファむルに䜎速のディスクを䜿甚する可胜性は䜎くなりたす。



制限



limitは非垞に単玔なので繰り返し䜿甚したしたが、それでも詳现に説明したす。 制限操䜜はサブ操䜜を開始し、サブ操䜜が返した最初のN行のみを返したす。 通垞、この埌、サブオペレヌションは停止したすが、堎合によっおはたずえば、pl / PgSQL関数の呌び出し、サブオペレヌションは最初の行を返すたでに䜜業をすでに完了しおいたす。



簡単な䟋



 $ explain analyze select * from pg_class; QUERY PLAN --------------------------------------------------------------------------------------------------------- Seq Scan on pg_class (cost=0.00..10.92 rows=292 width=203) (actual time=0.008..0.047 rows=295 loops=1) Total runtime: 0.096 ms (2 rows) $ explain analyze select * from pg_class limit 2; QUERY PLAN ------------------------------------------------------------------------------------------------------------- Limit (cost=0.00..0.07 rows=2 width=203) (actual time=0.009..0.010 rows=2 loops=1) -> Seq Scan on pg_class (cost=0.00..10.92 rows=292 width=203) (actual time=0.008..0.009 rows=2 loops=1) Total runtime: 0.045 ms (3 rows)
      
      





ご芧のずおり、2番目のケヌスで制限を䜿甚するず、ネストされたSeqスキャン操䜜が2行を怜出した盎埌にその䜜業を完了したずいう事実に至りたした。



ハッシュ集蚈



この操䜜は䞻に、GROUP BYおよびsum、avg、min、maxなどの䞀郚の集蚈を䜿甚する堎合に䜿甚されたす。



䟋



 $ explain analyze select relkind, count(*) from pg_Class group by relkind; QUERY PLAN ------------------------------------------------------------------------------------------------------------- HashAggregate (cost=12.38..12.42 rows=4 width=1) (actual time=0.223..0.224 rows=5 loops=1) -> Seq Scan on pg_class (cost=0.00..10.92 rows=292 width=1) (actual time=0.008..0.053 rows=295 loops=1) Total runtime: 0.273 ms (3 rows)
      
      





HashAggregateは次を実行したす。受信する各行に察しお、GROUP BY“キヌ”この堎合はrelkindを芋぀けたす。 次に、ハッシュ連想配列、蟞曞で、このキヌが瀺すバスケットに遞択した行を配眮したす。



すべおの行が凊理された埌、ハッシュをスキャンし、キヌ倀ごずに1行を返し、必芁に応じお適切な蚈算合蚈、最小、平均などを行いたす。



HashAggregateは、少なくずも1行を返す前にすべおの行をスキャンする必芁があるこずを理解するこずが重芁です。



これを理解しおいる堎合、朜圚的な問題が発生しおいる可胜性がありたす。数癟䞇行ある状況で䜕をすべきか。 ハッシュは倧きすぎおメモリに収たりたせん。 そしお、ここで再びwork_memを䜿甚したす 。 生成されたハッシュが倧きすぎる堎合、ディスクにマヌゞされたす再び$ PGDATA / base / pgsql_tmpにありたす。



これは、プランにHashAggregateずSortの䞡方がある堎合、最倧2 * work_memを䜿甚できるこずを意味したす。 このような蚈画は簡単に入手できたす。



 $ explain analyze select relkind, count(*) from pg_Class group by relkind order by relkind; QUERY PLAN ------------------------------------------------------------------------------------------------------------------- Sort (cost=12.46..12.47 rows=4 width=1) (actual time=0.260..0.261 rows=5 loops=1) Sort Key: relkind Sort Method: quicksort Memory: 25kB -> HashAggregate (cost=12.38..12.42 rows=4 width=1) (actual time=0.221..0.222 rows=5 loops=1) -> Seq Scan on pg_class (cost=0.00..10.92 rows=292 width=1) (actual time=0.006..0.044 rows=295 loops=1) Total runtime: 0.312 ms (6 rows)
      
      





実際には、work_memは操䜜に察する制玄であるため、1぀の芁求でwork_memを䜕床も䜿甚できたす。 したがっお、リク゚ストが1000個のHashAggregatesずSortsおよびwork_memを䜿甚する他の操䜜を䜿甚する堎合、合蚈メモリ消費量が非垞に倧きくなる可胜性がありたす。



ハッシュ結合/ハッシュ



HashAggregateに぀いお説明したばかりなので、Hash Joinに進むのが論理的です。



この操䜜には、前の操䜜ずは異なり、 2぀のサブ操䜜がありたす。 それらの1぀は垞に「ハッシュ」で、2぀目は別のものです。



名前が瀺すように、ハッシュ結合は2セットのレコヌドを結合するために䜿甚されたす。 たずえば、次のように



 $ explain analyze select * from pg_class c join pg_namespace n on c.relnamespace = n.oid; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------- Hash Join (cost=1.14..16.07 rows=292 width=316) (actual time=0.036..0.343 rows=295 loops=1) Hash Cond: (c.relnamespace = n.oid) -> Seq Scan on pg_class c (cost=0.00..10.92 rows=292 width=203) (actual time=0.007..0.044 rows=295 loops=1) -> Hash (cost=1.06..1.06 rows=6 width=117) (actual time=0.012..0.012 rows=6 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 1kB -> Seq Scan on pg_namespace n (cost=0.00..1.06 rows=6 width=117) (actual time=0.004..0.005 rows=6 loops=1) Total runtime: 0.462 ms (7 rows)
      
      





これは次のように機胜したす最初に、Hash Joinが「Hash」を呌び出し、次に別の䜕かこの堎合はpg_namespaceによるSeq Scanを呌び出したす。次に、Hashはハッシュをメモリ内たたはサむズに応じおディスク䞊に䜜成したす/デヌタを結合するために䜿甚されるものを䜿甚しおハッシュ化された゜ヌスからの文字列を持぀連想配列/蟞曞この堎合、これはpg_namespaceのOID列です。



もちろん、指定された結合キヌに察しお倚くの行を持぀こずができたす䞻キヌず結合しおいるため、この堎合はそうではありたせんが、䞀般的には、1぀のハッシュキヌに察しお倚くの行があるでしょう。



Perl衚蚘では、ハッシュ出力は次のようになりたす。



 { '123' => [ { data for row with OID = 123 }, ], '256' => [ { data for row with OID = 256 }, ], ... }
      
      





次に、Hash Joinは2番目のサブオペレヌションこの堎合はpg_classによるシヌケンススキャンを開始し、そこからの各行に察しお次のこずを行いたす。

  1. 結合キヌこの堎合はpg_class.relnamespaceがハッシュ操䜜によっお返されるハッシュにあるかどうかを確認したす。
  2. そうでない堎合、サブオペレヌションのこの行は無芖されたす返されたせん。
  3. キヌが存圚する堎合、ハッシュ結合はハッシュから行を取埗し、この行に基づいお䞀方で、すべおのハッシュ行で行出力を生成したす。


結合の䞡偎が䞀床だけ実行されるこずに泚意するこずが重芁ですこの堎合、䞡方ずもseqスキャンです、最初に、ハッシュ操䜜によっお呌び出されたものはハッシュに栌玍されたすべおの行を返し、2番目は行ごずに凊理されたす、ファヌストパヌティハッシュに存圚しない行はスキップされたすハッシュが豊富であるにもかかわらず、この文が明確であるこずを願っおいたす。



䞡方のサブスキャンは任意のタむプの操䜜である可胜性があるため、フィルタヌ、むンデックススキャン、たたは想像できるあらゆるものになる可胜性がありたす。



Hash Join / Hashに関しお最埌に蚀及する䟡倀があるのは、Hash操䜜は、SortやHashAggregateず同様に、work_memたでのメモリを䜿甚するこずです。



ハッシュ結合/ハッシュ



組合に぀いお話しおいるので、ネストルヌプに぀いお議論する䟡倀がありたす。 䟋



 $ explain analyze select a.* from pg_class c join pg_attribute a on c.oid = a.attrelid where c.relname in ( 'pg_class', 'pg_namespace' ); QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------------------- Nested Loop (cost=0.28..52.32 rows=16 width=203) (actual time=0.057..0.134 rows=46 loops=1) -> Seq Scan on pg_class c (cost=0.00..11.65 rows=2 width=4) (actual time=0.043..0.080 rows=2 loops=1) Filter: (relname = ANY ('{pg_class,pg_namespace}'::name[])) Rows Removed by Filter: 291 -> Index Scan using pg_attribute_relid_attnum_index on pg_attribute a (cost=0.28..20.25 rows=8 width=203) (actual time=0.007..0.015 rows=23 loops=2) Index Cond: (attrelid = c.oid) Total runtime: 0.182 ms
      
      





これは、遞択した操䜜を耇数回実行できるため、非垞に興味深い蚈画です。



ハッシュ結合ず同様に、ネストされたルヌプには2぀の「子孫」がありたす。 たず、「Seq Scan」を起動しこの䟋では最初に最初のノヌドを起動したす、次に返された各行この䟋では2行のみで2番目の操䜜を開始したすこの䟋ではpg_attributeによるむンデックススキャン。



むンデックススキャンの実際のメタ情報に「ルヌプ= 2」があるこずに気づいたかもしれたせん。぀たり、この操䜜は2回実行され、他の倀行、時間はすべおの実行の平均倀です。



Explain.depesz.comから次の蚈画を芋おみたしょう。 カテゎリのすべおのむンデックススキャン操䜜の実際の実行時間は0.002〜0.003ミリ秒であるこずに泚意しおください。 ただし、このむンデックススキャンは26k回以䞊実行されたため、このノヌドで費やされた合蚈時間は78.852msです。



したがっお、凊理は次のようになりたす。

  1. ネストされたルヌプは、ナニオンの最初のサむドを䞀床起動したす。 圌女を「A」ず呌びたしょう。
  2. 「A」からの各行に぀いお、2番目の操䜜が開始されたす「B」ず呌びたしょう。
  3. 「B」が単䞀の行を返さなかった堎合、「A」からのデヌタは無芖されたす。
  4. 「B」が行を返した堎合、返された行ごずに、ネストされたルヌプはAおよびBの珟圚の行に基づいお新しい行を返したす。


結合を結合



別のデヌタマヌゞ方法は、マヌゞ結合ず呌ばれたす。 結合キヌを䜿甚しお結合可胜なデヌタセットが䞊べ替えられるたたは䜎コストで䞊べ替えられる堎合に䜿甚されたす。



既補の芖芚的な䟋はないので、結合する前にデヌタを゜ヌトするサブク゚リを䜿甚しお人為的に䜜成したす。



 $ explain analyze select * from ( select oid, * from pg_class order by oid) as c join ( select * from pg_attribute a order by attrelid) as a on c.oid = a.attrelid; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Merge Join (cost=23.16..268.01 rows=2273 width=410) (actual time=0.658..3.779 rows=2274 loops=1) Merge Cond: (pg_class.oid = a.attrelid) -> Sort (cost=22.88..23.61 rows=292 width=207) (actual time=0.624..0.655 rows=293 loops=1) Sort Key: pg_class.oid Sort Method: quicksort Memory: 102kB -> Seq Scan on pg_class (cost=0.00..10.92 rows=292 width=207) (actual time=0.011..0.211 rows=293 loops=1) -> Materialize (cost=0.28..212.34 rows=2273 width=203) (actual time=0.028..1.264 rows=2274 loops=1) -> Index Scan using pg_attribute_relid_attnum_index on pg_attribute a (cost=0.28..183.92 rows=2273 width=203) (actual time=0.015..0.752 rows=2274 loops=1) Total runtime: 4.009 ms (9 rows)
      
      





マヌゞ結合は、他のナニオンず同様に、2぀のサブオペレヌションこの堎合は゜ヌトずマテリアラむズを実行したす。 どちらも䞊べ替えられたデヌタを返し、䞊べ替え順序は結合操䜜の堎合ず同じなので、Pgはサブ操䜜によっお返された䞡方のデヌタセットをスキャンし、同時に識別子が䞀臎するかどうかを確認できたす。



手順は次のずおりです。



これは、デヌタセットを結合する非垞に䟿利な方法ですが、゜ヌトされた゜ヌスに察しおのみ機胜したす。 珟圚のExplain.depesz.comデヌタベヌスに基づいお、以䞋がありたす。



ハッシュ結合/ネストされたルヌプ/結合結合修食子



䞊蚘のすべおの䟋で、結合の䞡偎から文字列を受け取った堎合にのみ、結合操䜜が文字列を返すこずを瀺したした。



しかし、これは垞に起こるずは限りたせん。 巊、右、完党LEFT / RIGHT / FULL OUTER JOIN倖郚ア゜シ゚ヌションず、いわゆるアンチ結合を䜿甚できたす。



å·Š/右結合の堎合、操䜜の名前は次のように倉曎されたす。



ネストされたルヌプの右結合は存圚したせん。ネストされたルヌプは垞に巊偎から始たり、ルヌプの基瀎ずしお巊偎を䜿甚するためです。 したがっお、ネストされたルヌプで機胜する右結合を䜿甚する共甚䜓は、ネストされたルヌプ操䜜が機胜するように内郚的に巊結合に倉換されたす。



これらのすべおの堎合においお、論理は単玔です組合の2぀の偎面-巊ず右がありたす。 そしお、その偎がナニオンで蚀及されるず、 反察偎に察応する行がない堎合でも、新しい行を返したす。



これは、次のようなク゚リで発生したす。



 select * from a left join b on ...
      
      





たたは右結合。



ハッシュ結合/結合の結合ずネストされたルヌプに関するその他の情報はすべお同じで、ラむン出力が生成されるタむミングのロゞックにわずかな倉曎のみがありたす。



次の操䜜名を持぀完党結合ず呌ばれるバヌゞョンもありたす。



この堎合、どちらかの偎にデヌタがあるかどうかに関係なく、ナニオンは新しい行出力を生成したすデヌタが少なくずも片偎にある限り。 これは次の堎合に発生したす。



 select * from a full join b ...
      
      





前の䟋のように、すべおの凊理が発生したす。



さらに、いわゆるアンチ結合がありたす。 操䜜の名前は次のずおりです。



これらの堎合、Joinは、右偎で単䞀の文字列が芋぀からない堎合にのみ文字列を返したす。 これは、「WHERE not exists」たたは「left join ... where right_table.column is null」などの操䜜を行う堎合に圹立ちたす。



この䟋のように



 $ explain analyze select * from pg_class c where not exists (select * from pg_attribute a where a.attrelid = c.oid and a.attnum = 10); QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------------------------------- Hash Anti Join (cost=62.27..78.66 rows=250 width=203) (actual time=0.145..0.448 rows=251 loops=1) Hash Cond: (c.oid = a.attrelid) -> Seq Scan on pg_class c (cost=0.00..10.92 rows=292 width=207) (actual time=0.009..0.195 rows=293 loops=1) -> Hash (cost=61.75..61.75 rows=42 width=4) (actual time=0.123..0.123 rows=42 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 2kB -> Index Only Scan using pg_attribute_relid_attnum_index on pg_attribute a (cost=0.28..61.75 rows=42 width=4) (actual time=0.021..0.109 rows=42 loops=1) Index Cond: (attnum = 10) Heap Fetches: 0 Total runtime: 0.521 ms (9 rows)
      
      





ここで、Pgは右偎pg_attributeによるむンデックススキャンを実行し、ハッシュしおから巊偎pg_classによるSeqスキャンを実行し、指定されたpg_class.oidのHashに゚ントリがなかった行のみを返したした。



マテリアラむズ



この操䜜は、結合結合の䟋ですでに実蚌されおいたすが、他の堎合に圹立぀堎合がありたす。



Psqlには倚くの内郚コマンドがありたす。 それらの1぀は\ dTSで、すべおのシステムデヌタタむプをリストしたす。 内郚的に、\ dTSはこのリク゚ストを実行したす



 SELECT n.nspname as "Schema", pg_catalog.format_type(t.oid, NULL) AS "Name", pg_catalog.obj_description(t.oid, 'pg_type') as "Description" FROM pg_catalog.pg_type t LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid) AND pg_catalog.pg_type_is_visible(t.oid) ORDER BY 1, 2;
      
      





圌の蚈画はこれです



  QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------------------- Sort (cost=2783.00..2783.16 rows=65 width=68) (actual time=3.883..3.888 rows=87 loops=1) Sort Key: n.nspname, (format_type(t.oid, NULL::integer)) Sort Method: quicksort Memory: 39kB -> Nested Loop Left Join (cost=16.32..2781.04 rows=65 width=68) (actual time=0.601..3.657 rows=87 loops=1) Join Filter: (n.oid = t.typnamespace) Rows Removed by Join Filter: 435 -> Hash Anti Join (cost=16.32..2757.70 rows=65 width=8) (actual time=0.264..0.981 rows=87 loops=1) Hash Cond: ((t.typelem = el.oid) AND (t.oid = el.typarray)) -> Seq Scan on pg_type t (cost=0.00..2740.26 rows=81 width=12) (actual time=0.012..0.662 rows=157 loops=1) Filter: (pg_type_is_visible(oid) AND ((typrelid = 0::oid) OR (SubPlan 1))) Rows Removed by Filter: 185 SubPlan 1 -> Index Scan using pg_class_oid_index on pg_class c (cost=0.15..8.17 rows=1 width=1) (actual time=0.002..0.002 rows=1 loops=98) Index Cond: (oid = t.typrelid) -> Hash (cost=11.33..11.33 rows=333 width=8) (actual time=0.241..0.241 rows=342 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 14kB -> Seq Scan on pg_type el (cost=0.00..11.33 rows=333 width=8) (actual time=0.002..0.130 rows=342 loops=1) -> Materialize (cost=0.00..1.09 rows=6 width=68) (actual time=0.000..0.001 rows=6 loops=87) -> Seq Scan on pg_namespace n (cost=0.00..1.06 rows=6 width=68) (actual time=0.002..0.003 rows=6 loops=1) Total runtime: 3.959 ms
      
      





芋やすくするために、このプランもExplain.depesz.comにアップロヌドしたした 。



操䜜9はマテリアラむズであるこずに泚意しおください。 なんで



マテリアラむズはネストされたルヌプの巊結合-操䜜2によっお呌び出されたす。 ネストされたルヌプにより、遞択された操䜜が匷制的に耇数回、この堎合は87回実行されたす。



ナニオンの右偎は、pg_namespaceによるSeq Scanです。 そのため、理論的には、Postgresはpg_namespaceのシヌケンシャルスキャンを87回実行する必芁がありたす。 このテヌブルの1回の順次スキャンに0.003ミリ秒かかるこずを考慮するず、合蚈時間は玄0.25ミリ秒になるず予想できたす。



しかし、Postgresはよりスマヌトになっおいたす。 圌は、テヌブルを1回スキャンしお、すべおの行のむメヌゞをメモリに構築する方がコストが䜎いこずを理解しおいたす。 次に、テヌブルをスキャンする必芁がない堎合は、可芖性情報を確認し、デヌタペヌゞを解析したす。 単にメモリからデヌタを取埗したす。



これにより、すべおの合蚈時間テヌブルを1回読み取り、メモリにデヌタむメヌゞを準備し、このむメヌゞを87回スキャンするは0.087msでした。



あなたは蚀うこずができたす「しかし、なぜ結合は以前にマテリアラむズを䜿甚したのですか、それはたった1回のスキャンを実行したのですか」蚈画を思い出したしょう



 $ explain analyze select * from ( select oid, * from pg_class order by oid) as c join ( select * from pg_attribute a order by attrelid) as a on c.oid = a.attrelid; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Merge Join (cost=23.16..268.01 rows=2273 width=410) (actual time=0.658..3.779 rows=2274 loops=1) Merge Cond: (pg_class.oid = a.attrelid) -> Sort (cost=22.88..23.61 rows=292 width=207) (actual time=0.624..0.655 rows=293 loops=1) Sort Key: pg_class.oid Sort Method: quicksort Memory: 102kB -> Seq Scan on pg_class (cost=0.00..10.92 rows=292 width=207) (actual time=0.011..0.211 rows=293 loops=1) -> Materialize (cost=0.28..212.34 rows=2273 width=203) (actual time=0.028..1.264 rows=2274 loops=1) -> Index Scan using pg_attribute_relid_attnum_index on pg_attribute a (cost=0.28..183.92 rows=2273 width=203) (actual time=0.015..0.752 rows=2274 loops=1) Total runtime: 4.009 ms (9 rows)
      
      





, . , Merge Join . ( ), , ( ).



- Materialize , ( Index Scan), , .



, Materialize ( ), , , .



今日は以䞊です。私はこれを終了するず思ったが、説明する䟡倀のある操䜜がさらにたくさんあるので、このシリヌズでは少なくずも2぀の投皿残りの操䜜ず統蚈情報がありたす。



All Articles