EXPLAIN の種類
AST— 抽象構文木。SYNTAX— AST レベルでの最適化後のクエリテキスト。QUERY TREE— クエリツリー レベルでの最適化後のクエリツリー。PLAN— クエリ実行プラン。PIPELINE— クエリ実行パイプライン。ANALYZE— クエリを実行し、計測されたランタイムメトリクスを実行計画に注釈として付加します。ESTIMATE— クエリの処理中にテーブルから読み取ると見積もられる行数、マーク数、パーツ数。TABLE OVERRIDE— テーブル関数のスキーマに対するテーブルオーバーライドの検証済み結果。
EXPLAIN AST
クエリASTをダンプします。SELECT だけでなく、あらゆる種類のクエリをサポートします。
設定:
graph– DOT グラフ記述言語で記述されたグラフとして AST を出力します。デフォルト: 0。
EXPLAIN SYNTAX
構文解析後のクエリの抽象構文木 (AST) を表示します。 これは、クエリをパースしてクエリASTとクエリツリーを構築し、必要に応じてクエリアナライザと最適化パスを実行したうえで、クエリツリーをクエリASTに再変換することで行われます。 設定:oneline– クエリを1行で表示します。デフォルト:0。run_query_tree_passes– クエリツリーをダンプする前にクエリツリーパスを実行します。デフォルト:0。query_tree_passes–run_query_tree_passesが設定されている場合、実行するパス数を指定します。query_tree_passesを指定しない場合は、すべてのパスが実行されます。single_record– 整形されたクエリを、行ごとに1レコードではなく単一の複数行レコードとして返します。デフォルト:1(explain_syntax_single_record設定で制御) 。従来の1行1レコード出力に戻すには、0を設定するか、explain_syntax_single_record = 0を設定します (グローバルまたはクエリごとのSETTINGS内) 。または、compatibilityを26.8より前の任意のバージョンに設定します。
Query
Response
run_query_tree_passes を指定した場合:
Query
Response
EXPLAIN QUERY TREE
設定:run_passes— クエリツリーをダンプする前に、すべてのクエリツリーパスを実行します。デフォルト:1。dump_passes— クエリツリーをダンプする前に、使用されるパスの情報をダンプします。デフォルト:0。passes— 実行するパスの数を指定します。-1に設定すると、すべてのパスを実行します。デフォルト:-1。dump_tree— クエリツリーを表示します。デフォルト:1。dump_ast— クエリツリーから生成されたクエリ AST を表示します。デフォルト:0。
EXPLAIN PLAN
クエリプランのステップを出力します。 設定:optimize— プランを表示する前に、クエリプランの最適化を適用するかどうかを制御します。デフォルト: 1。header— ステップの出力ヘッダーを表示します。デフォルト: 0。description— ステップの説明を表示します。デフォルト: 1。indexes— 使用された索引、フィルタリングされたパーツ数、および適用された各索引についてフィルタリングされたグラニュール数を表示します。デフォルト: 0。MergeTree テーブルでサポートされています。ClickHouse >= v25.9 以降、このステートメントが適切な出力を示すのは、SETTINGS use_query_condition_cache = 0, use_skip_indexes_on_data_read = 0とともに使用した場合のみです。projections— 解析されたすべてのプロジェクションと、プロジェクションの主キー条件に基づくパーツレベルのフィルタリングへの影響を表示します。各プロジェクションについて、このセクションには、プロジェクションの主キーを使って評価されたパーツ数、行数、マーク数、範囲数などの統計が含まれます。また、このフィルタリングにより、プロジェクション自体を読み取ることなくスキップされた data parts の数も表示します。プロジェクションが実際に読み取りに使用されたのか、それともフィルタリングのために解析されただけなのかは、descriptionフィールドで判別できます。デフォルト: 0。MergeTree テーブルでサポートされています。actions— ステップの actions に関する詳細情報を表示します。デフォルト: 1。sorting— ソート済みの出力を生成する各プランステップについて、ソートの説明を表示します。デフォルト: 0。keep_logical_steps— joins について、物理的な join 実装に変換せずに、論理プランステップを保持します。デフォルト: 0。json— クエリプランのステップを JSON フォーマットの 1 行として出力します。デフォルト: 0。不要なエスケープを避けるため、TabSeparatedRaw (TSVRaw) フォーマットの使用を推奨します。input_headers— ステップの入力ヘッダーを表示します。デフォルト: 0。主に、入力ヘッダーと出力ヘッダーの不一致に関する問題をデバッグする開発者にのみ有用です。column_structure— ヘッダー内のカラム構造を、名前と型に加えて表示します。デフォルト: 0。主に、入力ヘッダーと出力ヘッダーの不一致に関する問題をデバッグする開発者にのみ有用です。distributed— 分散テーブルまたは並列レプリカについて、リモートノードで実行されるクエリプランを表示します。jsonと同時にはサポートされません。デフォルト: 0。compact— 有効にすると、プランから expression ステップと詳細な action 情報 (入力、関数、別名、出力位置) を非表示にします。actions = 1の場合にのみ効果があります。デフォルト: 1。pretty— インデントの代わりに罫線文字 (├──、└──、│) を使ってプランツリーを表示し、階層構造を視覚化します。さらに、join ステップのプロパティもインラインで整形して表示します。デフォルト: 1。
デフォルトでは、
explain_query_plan_default = 'pretty' であるため、actions、compact、pretty は 1 に初期化され、プランはコンパクトで見やすく、action 注釈付きの形式で描画されます。EXPLAIN ステートメントでこれらのオプションのいずれかを明示的に指定した場合 (たとえば、EXPLAIN actions = 0, compact = 0, pretty = 0 SELECT ...) は、常にその指定がデフォルトを上書きします。ClickHouse 26.7 より前では、actions、compact、pretty のデフォルトは 0 でした。その出力は、explain_query_plan_default = 'legacy' を設定する (グローバル、またはクエリごとの SETTINGS で設定する) か、compatibility を 26.7 より古い任意のバージョンに設定することで、引き続き取得できます。json と distributed オプションでは、explain_query_plan_default = 'pretty' の場合でも、pretty のデフォルト (actions、compact、pretty) は有効になりません。出力に action の詳細を含めるには、actions = 1 を手動で設定してください。Step およびクエリのコスト見積もりはサポートされていません。
json = 1 の場合、クエリプランは JSON フォーマットで表されます。各ノードは辞書で、常に Node Type、Node Id、Plans のキーを持ちます。Node Type はステップ名を表す文字列で、Node Id は一意のステップ識別子です (数値の接尾辞が付いたステップ名。例: Union_10) 。Plans は子ステップの説明を含む配列です。その他の任意のキーは、ノードの種類や設定に応じて追加されることがあります。
例:
description = 1 の場合、Description キーがステップに追加されます。
header = 1 の場合、Header キーがカラムの配列としてステップに追加されます。
例:
indexes = 1 の場合、Indexes キーが追加されます。これには、使用された索引の配列が含まれます。各索引は JSON で記述され、Type キー (文字列 Partition Min-Max、Partition、Statistics、PrimaryKey または Skip) と、必要に応じて以下のキーを持ちます。
Statistics 索引は、パーツごとのカラム STATISTICS (最小値/最大値、および Nullable カラムにおける NULL 値の数) を使用して、クエリのフィルタに一致し得ないパーツをスキップします。
Name— 索引名 (現在はSkip索引でのみ使用) 。Keys— 索引で使用されるカラムの配列。Condition— 使用された条件。Description— 索引の説明 (現在はSkip索引でのみ使用) 。Parts— 索引の適用後/適用前のパーツ数。Granules— 索引の適用後/適用前のグラニュール数。Ranges— 索引の適用後のグラニュール範囲数。
projections = 1 を指定すると、Projections キーが追加されます。これには、分析されたプロジェクションの配列が含まれます。各プロジェクションは、以下のキーを持つ JSON として記述されます:
Name— プロジェクション名。Condition— プロジェクションで使用された主キー条件。Description— プロジェクションの使用方法の説明 (例: パーツレベルのフィルタリング) 。Selected Parts— プロジェクションによって選択されたパーツ数。Selected Marks— 選択されたマーク数。Selected Ranges— 選択された範囲数。Selected Rows— 選択された行数。Filtered Parts— パーツレベルのフィルタリングによってスキップされたパーツ数。
actions = 1 の場合、追加されるキーはステップの種類によって異なります。
例:
compact = 0 かつ actions = 1 を指定すると、Expression ステップとともに式に関する詳細情報を確認できます:
distributed = 1 を指定すると、出力にはローカルのクエリプランだけでなく、リモートノードで実行されるクエリプランも含まれます。これは、分散クエリの分析やデバッグに役立ちます。
distributed は、pretty 出力ではリモート分片のプランがプランツリーに統合されないため、legacy (非pretty) 形式でのみ表示されます。このため、distributed を有効にすると、explain_query_plan_default の値に関係なく、pretty のデフォルト設定 (actions、compact、pretty) は自動的に無効になります。なお、actions=1 は手動で設定できます。また、distributed オプションは json と併用できません。pretty = 1 を指定すると、プランツリーはインデントの代わりに罫線文字で表示され、主要なステップの追加情報も表示されます:
- クエリ出力カラム はプランの先頭に表示されます。
- フィルタ、集約キー、ソートの説明、ウィンドウ関数内の 式 は、人が読める SQL 風の表記で表示されます (例:
greater(plus(a, 1), 5)ではなくa + 1 > 5) 。わかりやすさのため、内部カラム識別子のプレフィックス (__table1.など) は削除されます。 - ソースステップ (
ReadFromMergeTreeなど) には、その出力カラムが表示されます。 - フィルタステップ には、SQL 表記のフィルタ条件が表示されます。ランタイム join フィルタが存在する場合は、それらは別個に表示されます。
- 集約ステップ には、キーと、引数付きの集約関数 (例:
sum(c)、count()) が表示されます。 - タプルリテラルの IN set にはその値が表示され (大きな set の場合は切り詰められます) 、サブクエリベースの set には
subquery1、subquery2などのラベルが付き、Setengine tables 由来の set にはテーブル名が表示されます。 - join ステップ には、数学的記法を用いた join 関係、そのステップについて join 順序最適化器が生成した推定値 (コスト、選択性、出力行数、各側の行数)、 および各側の入力カラムが表示されます。異なる join タイプを表すために、次の記号が使用されます:
たとえば、
t1 ⟕ t2 はテーブル t1 と t2 の間の left join を意味します。
テーブル名の後の角括弧内の数値 (例: t1[100]) は、テーブル統計情報が利用可能な場合の推定行数を
示します。
join 関係の下には、各 join ステップについて join 順序最適化器が生成した推定値が表示されます:
Cost— このステップ配下の join サブツリー全体のコストであり、オプティマイザが候補となる JOIN 順序を 比較する際に最小化する値です。join のコストは、結合した行ペアの推定数<selectivity> * <left_rows> * <right_rows>に入力のコストを加えたものです。Selectivity— 2 つの側のデカルト積のうち、join 条件を満たして残ると推定される割合です。 これは結合キーの distinct values (NDV) 数から導出されます。 キーの等価条件ではペアの約1 / max(NDV_left, NDV_right)が残り、join 条件全体では 最小の割合が使用されます。Output rows— join が生成する推定行数です。 inner join では<selectivity> * <left_rows> * <right_rows>、LEFTでは<left_rows>、RIGHTでは<right_rows>、FULLでは<left_rows> + <right_rows>を下限とします。これは outer join が保持側のすべての行を残すためです。SEMIまたはANTIjoin が並べ替えに 関与する場合は、保持側の割合として推定されます。SEMIでは<preserved_rows> * min(1, <selectivity> * <other_rows>)、ANTIでは残りの行数です。 それ以外の場合は、その join 種別の式を使用します。Left/Right— 各側から join に入力される推定行数です。
no stats として報告されます。これは、
join 順序の最適化が実行されなかった場合、たとえば
query_plan_optimize_join_order_limit
が 0 の場合、または推定の根拠がない場合に発生します。
Input (left): および Input (right): の行には、各側が join に入力するカラムが一覧表示されます。
pretty オプションは compact = 1 と組み合わせて使用すると効果的です。これにより、Expression ステップと詳細な action 情報が非表示になり、プランが読みやすくなります。
join を含む詳細な例です。
join_runtime_filter_min_probe_rows
設定は、この程度に小さいテーブルでもランタイム join フィルタが構築されるようにするためだけに引き下げています。
EXPLAIN PIPELINE
設定:header— 各出力ポートのヘッダーを表示します。デフォルト: 0。graph— DOT グラフ記述言語で記述されたグラフを表示します。デフォルト: 0。compact—graph設定が有効な場合、compact モードでグラフを表示します。デフォルト: 1。compact_repeated_processor_chains— テキスト出力で、隣接して繰り返されるプロセッサチェーンを、チェーンを 1 つだけ表示して繰り返し回数を付けることでコンパクトにします。これにより、たとえば JOIN で同じチェーンが何度も現れる場合に、並列パイプラインが読みやすくなります。グラフ出力には影響しません。デフォルト: 0。
compact=0 かつ graph=1 の場合、プロセッサ名には一意のプロセッサ識別子を示す追加の接尾辞が含まれます。
例:
EXPLAIN ANALYZE
EXPLAIN ANALYZE は実際にクエリを実行し、結果の行を破棄したうえで、各ステップに実行時に実際に何が起きたかを注記として付けた、EXPLAIN PLAN と同じプランツリーを出力します。
設定:
EXPLAIN ANALYZE では、EXPLAIN PLAN と同じ表示オプションを使用できます (EXPLAIN PLAN セクションを参照) 。
header— EXPLAIN PLAN セクションを参照してください。description— EXPLAIN PLAN セクションを参照してください。projections— EXPLAIN PLAN セクションを参照してください。sorting— EXPLAIN PLAN セクションを参照してください。input_headers— EXPLAIN PLAN セクションを参照してください。column_structure— EXPLAIN PLAN セクションを参照してください。actions— EXPLAIN PLAN セクションを参照してください。デフォルト: 1。indexes— EXPLAIN PLAN セクションを参照してください。デフォルト: 1。compact— EXPLAIN PLAN セクションを参照してください。デフォルト: 1。pretty— EXPLAIN PLAN セクションを参照してください。デフォルト: 1。processors—EXPLAIN ANALYZEでは、各ステージについて、プロセッサごとの経過時間分布 (min、median、max、sum) を示す追加の行を出力します。並列プロセッサ間の負荷の偏りを見つけるのに役立ちます。デフォルト: 0。matches—EXPLAIN ANALYZEでは、結合による出力だけではこれらの数値を導出できない場合に、matched、match rate、fanoutメトリクスに必要な追加の記録処理を join ステップで行います。導出できる場合は、このオプションなしで報告されます。join ステップを参照してください。デフォルト: 0。time—EXPLAIN ANALYZEでは、各ステップとそのブランチの実時間と並列実行レベルを示すTime行とConcurrency行をステップごとに出力します。ステップとブランチの実時間と同時実行レベルを参照してください。デフォルト: 1。
EXPLAIN ANALYZE はラップされたクエリを実際に実行するため、いくつかの点で、そのクエリと同じように動作し、実行しない EXPLAIN 形式とは異なります。- クォータと制限。 クエリを直接実行した場合と同じ quotas
に対してカウントされ、同じ limits
(たとえば
query_selects、read_rows) の対象にもなります。プランニング中はクォータの対象外となるテーブル (system.oneなど) についてはカウントされません。 - 失敗したトランザクション。 すでに失敗している transaction
(
ROLLED_BACK) 内では、通常のSELECTと同様にINVALID_TRANSACTIONで拒否されます。 先にROLLBACKを実行してください。 - ストリーミング読み取り。 ストリーミング (
FROM ... STREAM) 読み取りに対しては、 そのような読み取りは完了しないため、NOT_IMPLEMENTEDで拒否されます。 - 分散クエリ。 distributed モードで実行される クエリではサポートされていません。
Time— 合計時間です。planning (つまり、plan の作成 + plan の最適化 + パイプラインの構築) フェーズと execution (パイプラインの実行) フェーズに分けて表示されます。Execution—time = 0の場合は表示されません。実行時間をin steps、outside steps、idleに分けて表示します。これらの合計がexecutionになります。ステップとブランチの実時間と同時実行レベルを参照してください。Read— テーブルから読み取られた行数と非圧縮バイト数、および throughput です。これは通常のクエリのフッターで “Processed” として報告される数値と同じです。Peak memory— クエリが使用したピークメモリです。
I/O 行) 。時間と並列度は、ステップ内の各ステージごとに、その下のインデントされた行に報告されます。
rows <in> → <out>— ステップに入力された行数と、ステップから出力された行数です。(<selectivity>%) は、そのステップがデータをどの程度絞り込んだか (out/in) 、または増やしたかを示します。入力行数と出力行数が同じ場合、および入力行数が0の場合は表示されません。<bytes_in> → <bytes_out>— ステップ内を流れる非圧縮のインメモリバイト数です (両方ともゼロの場合は省略されます) 。time <t> (<share>%)— そのステージがアクティブだった実時間と、クエリ実行時間に占める割合です (つまり、build time は含みません) 。ステージやステップは同時実行されるため、この割合の合計が 100% を超えることがあります。parallelism <avg>/<max>— このステージ内で同時に動作していた CPU スレッド数の平均値と、そのステージで使用可能な最大値です。このメトリクスはステージ単位のもので、同時にクエリ内の他のステップで動作するスレッドは含まれません。値が最大値に近いほど、そのステージは十分に並列化されていたことを示します。1 に近い場合は、ほぼ直列に実行されていたことを示します。Stage (<stage>)— ステージ名です。ステージが 1 つだけのステップでは、Stage (...)ラベルは付かず、時間の行が直接出力されます。複数のステージを持つステップでは、各ステージごとにラベル付きの行が 1 行ずつ出力されます。たとえばAggregatingではStage (partial aggregation)とStage (final aggregation)が表示され、ハッシュ結合ではStage (build)とStage (probe)が表示されます。
ClickHouse は、プランステップ内のタスク実行だけでなく、プランステップ自体の実行も並列化します。
parallelism メトリクスが反映するのは、このステップの処理だけです。他のステップも同時に実行されることがあるため、この数値から、このステップの並列度をクエリ全体と比較することはできません。クエリ全体の状況を確認するには、time = 1 とともに表示される Concurrency メトリクスを参照してください (ステップとブランチの実時間と同時実行レベル) 。parallelism の最大値は、次の 2 つのうち小さい方として計算されます。- プランステップ内のタスク総数
max_threadsで設定されたクエリ処理スレッドの最大数
結合 ステップ
結合 ステップでは、EXPLAIN ANALYZE は結合順序オプティマイザの推定値と実際に起きたことを比較する行 (推定値と実測値の join メトリクス を参照) と、各側の参加行 (Left と Right) を出力し、その後に 結合 の実装固有の行を出力します。Left と Right は SQL 上の論理的な側に対応します。ほとんどの場合、Left は 結合 のプローブ側、Right は 結合 のビルド側にもなります。ただし、結合 の実行中に入れ替え (swap) が発生することがあるため、常にそうなるとは限りません。join_algorithm のすべての値 (hash、parallel_hash、grace_hash、partial_merge、full_sorting_merge、parallel_full_sorting_merge、direct) に対応しています。また、この設定では選択できない 3 つの実装、すなわち CROSS または COMMA 結合、結合キーが定まらない ON 句を受け取る block nested loop 結合、および Join テーブルエンジンも対象です。ほとんどの実装では両側が報告されますが、マテリアライズする側のみを報告するものもあります (たとえば、direct は Left: のみを出力します) 。
各側の行は同じ形式です。
EXPLAIN ANALYZE は以下を報告します。
rows estimated <estimated_rows>— 結合順序オプティマイザによるその側の行数の推定値。隣に表示される実際のrowsとの比較用に出力されます。オプティマイザが推定値を生成しなかった場合はno statsとなります (「推定値と実測値の join メトリクス」を参照) 。rows <rows>— 結合処理を通過したその側の行の総数。matched <matched_rows>— もう一方の側で少なくとも1つの結合相手が見つかった、その側の行数。これはキーではなく行を数えます。キーが右側に3回出現して一致した場合、右側の3行すべてが一致した行としてカウントされます。match rate <match_rate>%— 一致したその側の行の割合。100 * <matched_rows> / <rows>として算出されます。fanout <fanout>— その側で一致した行1行あたりが平均して生成する出力行数。
0 ではなく not collected として報告されます。match rate と fanout は matched から導出されるため、matched がない側では、3つすべてが not collected として報告されます。
推定値と実測値の join メトリクス
join ステップは、結合順序オプティマイザによる推定値 (EXPLAIN PLAN が表示するものと同じ値。EXPLAIN PLAN セクションを参照) を保持しており、EXPLAIN ANALYZE はそれぞれを実測値と並べて出力します。
Cost— どちらの値も、マッチした出力行数を表します。推定値は、オプティマイザによる join 部分木のコストで、<selectivity> * <left_rows> * <right_rows>にその入力のコストを加えたものです。実測値も同様に算出され、この join のマッチした出力行数に、同じ並べ替えクラスターに属する下位のすべての join の実コストを加えたものです。Selectivity— 推定値は結合キーの個別値数から導出されます。実測値は、出力に含まれたデカルト積の割合を計測したもので、<matched output rows> / (<left rows> * <right rows>)です。これはオプティマイザが推定しようとする値です。Output rows— join が生成した推定行数と実測行数です。両方がゼロ以外の場合、q-errorはカーディナリティ推定の品質を測る標準的な指標であるmax(estimated / actual, actual / estimated)を報告します。1.00は完全な推定を意味し、大きな値は、オプティマイザが大きく誤ったカーディナリティに基づいて JOIN 順序を選択したことを意味します。
no stats として報告されます。たとえば、query_plan_optimize_join_order_limit が 0 であるため、JOIN 順序の最適化が実行されなかった場合です。これは、実行時に計測できなかった実測値を示す not collected とは異なります。右側が事前に入力済みの join (Join テーブルエンジン、direct join) は 結合順序オプティマイザを経由せず、参加行のみを出力します。
join ステップでは、各辺が join に渡すカラムを示す Input (left): 行と Input (right): 行も出力されます。
EXPLAIN PLAN の join 例で使用するテーブルでは、EXPLAIN ANALYZE SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id の join ステップは次のようになります:
ファンアウト
fanout は行数の増加倍率を示します。
NULL で埋められた出力行が 1 行生成されます。これらの行は比率を薄めないよう差し引かれます。このような行が存在するのは保持側のみです。RIGHT と FULL では右側、LEFT と FULL では左側になります。
fanout = 0— 一致した行からは出力行がまったく生成されません。これはANTIjoin の動作であり、相手が見つからなかった行のみを出力します。fanout = 1— 明確な 1:1 join です。一致した各行から、ちょうど 1 行の出力行が生成されます。fanout > 1— 1:N join です。もう一方の側の重複キーによって行数が増加しました。両側で同時に大きな値になる場合は、意図しない Cartesian 的な行数の急増を示します。
数値に matches = 1 が必要な場合
これらの数値の大半は、結合がいずれにせよ構築するデータから得られるため、通常の EXPLAIN ANALYZE で報告されます。残りは、結合が通常は行わない追跡処理を必要とするため、EXPLAIN ANALYZE matches = 1 でのみ報告されます。どれが該当するかはアルゴリズムによって異なり、hash ファミリーでは次の 2 つです。
- 一致したすべての右行に印を付ける必要がある、
ALL INNERとALL LEFTの右側。 ALL LEFTとALL FULLの左側。ただし、クエリが右テーブルから何も選択せず、ONセクションが単純なキーの等価条件である場合に限ります。それ以外の場合、プローブはすでに 一致した左行を記録します。これは右カラムをマテリアライズするため、または残余条件を評価するためです。 そのため、このオプションがなくてもカウントは正確です。
partial_merge では、同じ理由で 4 種類の ALL の右側に必要です。
full_sorting_merge と parallel_full_sorting_merge では、ANY 種類の両方の側に必要です。
ALL 種類では何も必要ありません。
追加の追跡処理にはコストがかかり、計測精度に影響します。そのため、このオプションはデフォルトで無効になっています。処理はプローブループ内で実行され、出力行数に応じて増加します。左行と右行が相手側で正確に何件一致したかを知る必要がある場合は、
matches = 1 を使用してください。matches = 1 を指定しても、すべての組み合わせで収集できるようになるわけではありません。結合がどちらの側を報告できるかは、その結合がいずれにせよ実行する必要がある処理によるため、種類や厳密性だけでなくアルゴリズムにも依存します。
Hash ファミリー。 hash、parallel_hash、grace_hash は常に同じ結果になります。
結合がハッシュテーブル内でキーごとに 1 行だけを保持する場合、右側は収集できません。これは
ANY、SEMI、ANTI 結合で行われます。重複する右行は保存されないため、カウントできません。別の左行によってすでに相手が確保されている左行の出力を結合が抑制する場合、左側は収集できません。この場合、出力される行数は一致した行数より少なくなります。
any_join_distinct_right_table_keys を有効にすると、ANY は以前の RightAny セマンティクスに切り替わります。このセマンティクスでは左行ごとに 1 行が出力されるため、両方のカウントが保持されます。その場合、ANY RIGHT と ANY FULL は両方の側を報告し、ANY INNER は SEMI LEFT に書き換えられます。
Join テーブルエンジンも同じ表に従い、エンジンで宣言された種類と厳密性を使用します。Join(ALL, INNER, …) は両方の側を報告し、Join(ANY, LEFT, …) はどちらも報告しません。
マージアルゴリズム。 full_sorting_merge と parallel_full_sorting_merge は、4 種類の ALL、ANY INNER、ANY LEFT、ANY RIGHT、ASOF、ASOF LEFT を受け入れます。ASOF と ASOF LEFT を除くすべての種類で両方の側を報告します。これらでは右側が not collected になります。また、matches = 1 も不要です。2 つのソート済み入力を走査し、処理中に等しい範囲にあるすべての行を確認するため、後から再構築する必要がないからです。
partial_merge は ALL INNER、ALL LEFT、ALL RIGHT、ALL FULL、ANY INNER、ANY LEFT、SEMI LEFT を受け入れます。4 種類の ALL では両方の側を報告しますが、右側には matches = 1 が必要です。ANY INNER、ANY LEFT、SEMI LEFT では右側が not collected になります。
direct。 左側のみです。右側は行としてマテリアライズされないキー・バリューストアであるため、Right: 行自体がありません。
CROSS、COMMA、定数の ON。 前述のとおり、どちらの側も報告されません。
ブロックネステッドループ結合。 結合キーを定めない ON セクションを受け取るオペレーターです。ただし、それより前のいずれかのパスがその条件を引き受ける場合は除きます (allow_block_nested_loop_join を参照) 。ASOF、PASTE、ANY FULL を除く、すべての種類と厳密性を受け付けます。
オペレーターがどの左側の行が一致したかをすでに記録している場合、左側はこのオプションなしで報告されます。一致しなかった左側の行を保持する種類ではいずれもその記録が必要であり、左側の行ごとに最大 1 つのペアしか取らない厳密性でも同様です。右側は、オペレーターが一致フラグを保持している場合に報告されます。一致フラグは
RIGHT、FULL、および右側駆動の SEMI/ANTI で必要になります。ANY INNER もフラグを保持しますが、その目的は右側の行を単一の左側の行に割り当てることだけです。すでにペアを持つ左側の行については引き受けを止めるため、フラグはすべての一致ではなく結果のペアを示すものとなり、報告されません。ALL INNER がこのオペレーターに到達するのは hash が無効な場合のみです。それ以外の場合、条件はフィルタ付きの CROSS JOIN になります。
any_join_distinct_right_table_keys を有効にすると、ここでも ANY が RightAny のセマンティクスに切り替わり、左側はすべての種類で、右側は RIGHT と FULL で報告されます。ANY INNER は SEMI LEFT に書き換えられます。
2 つのアルゴリズムがともに数値を報告する場合、その数値は一致します。マージアルゴリズムは単により多くの情報を持っているだけで、何を一致とみなすかについて見解が食い違うことはありません。
アルゴリズム固有の行
各結合実装がこれに加えて出力する行を見てみましょう。hash および parallel_hash 結合、ならびに Join テーブルエンジンでは、Hash table: 行に右テーブルから構築されたハッシュテーブルの情報が表示されます。
unique keys <unique_keys>— ビルドフェーズ中にハッシュテーブルに格納された一意のキーの数。memory <peak_memory>— ビルドフェーズ中にハッシュテーブルが使用したピークメモリ。
grace_hash 結合 では、Hash table: 行に、結合 がメモリ制限にどのように適応したかも表示されます。また、Spill: 行には、データがディスクにスピルされたかどうかが表示されます。
buckets <buckets>— 実行終了時点で Grace Hash 結合 に含まれるバケット数です。常に2のべき乗になります。rehashes <rehashes>— メモリ制限内に収めるために、バケット数を 2 倍にする必要があった回数です。Spill:— ディスクへのスピリングが発生したかどうかを示すyes/noフラグです。発生した場合、left spilled <left_spilled_bytes>とright spilled <right_spilled_bytes>は、それぞれ左側 (probe) と右側 (build) でスピリングされた圧縮バイト数を示します。スピリングが発生しなかった場合、この行は単にSpill: noとなります。
partial_merge 結合では、Right: 行に右テーブルのバッファリング方法とソート方法に関する追加情報が含まれ、ソート時間は Stage (build) 行と Stage (probe) 行に表示されます。
size <right_size>— 右テーブルのブロックのメモリ使用量。blocks <right_blocks>— 右テーブルがバッファリングされたブロック数。storage <in-memory|external>— 右テーブルがメモリに収まったか (in-memory) 、またはディスクにスピルする必要があったか (external) 。externalの場合、追加のspilled <spilled_bytes>にディスクに書き込まれた圧縮バイト数が表示されます。sort time <sort_time>— 右テーブルのソート (build ステージ) と、受信した各左ブロックのソート (probe ステージ) に費やされた時間。sort share <sort_share>%— ステージのtimeの割合がクエリ全体の実行時間に占める割合であるのに対し、sort timeがそのステージ自体のビジー時間 (各プロセッサの経過時間の合計) に占める割合。
full_sorting_merge 結合 では、共通の Left: 行と Right: 行のみが出力されます。
direct 結合 では、右側は行としてマテリアライズされず直接ルックアップされるキー・バリューストアであるため、Left: 行のみが出力されます。
CROSS または COMMA 結合、および ON セクションにキーの等価条件を含まない ALL INNER JOIN (planner はこれを、その条件をフィルタとする CROSS JOIN に変換します) では、Buffer: 行に右テーブルがメモリ内でどのように保持されたかが示され、Spill: 行にディスクにスピルされたかどうかが表示されます。
memory <peak_memory>— バッファリングされた右テーブルが使用したピークメモリ。compressed <yes|no>— バッファリングされたブロックが少なくとも1つ圧縮されているかどうか。圧縮されている場合、リーダー は保存されているすべてのブロックを伸長します。Spill:—grace_hashと同じyes/noフラグで、right spilled <right_spilled_bytes>はディスクに書き込まれた圧縮バイト数を示します。
matched not collected が報告されます。定数の predicate では、すべての左行がすべての右行と組み合わされるか、まったく組み合わされないかのいずれかとなるため、個々のどの行が一致したかを特定することはできません。
キーの等価条件を持たないその他すべての ON 句を処理する block nested loop 結合 も、マテリアライズする右テーブルについて同じ 2 行を出力します。
memory <peak_memory>— 格納された右テーブルが占有したピークメモリです。すべてのブロックが到着時にディスクへ書き込まれた場合は、どのブロックもメモリに保持されなかったため0になります。compressed <yes|no>— 格納されたブロックのうち少なくとも1つが圧縮されているかどうかを示します。圧縮されている場合、リーダーは格納されたすべてのブロックを伸長します。Spill:—grace_hashと同じyes/noフラグです。right spilled <right_spilled_bytes>は、ディスクに書き込まれた圧縮バイト数を示します。
CROSS の場合とは異なり、ここではオペレーターが調べる各ペアに対して実際の条件を評価するため、両側とも matched を報告する可能性があります。どちらが報告するかについては、上記の表を参照してください。
Join テーブルエンジンとの 結合 では、事前構築済みテーブルを説明する Hash table: 行とともに、両側が報告されます。右側では、クエリごとの build の行数ではなく、エンジンに格納されている行数がカウントされます。
プロセッサごとの時間
processors = 1 の場合、各ステージの下に追加の行が出力され、そのステージのプロセッサごとの経過時間の分布が表示されます。
<n> はそのステージのプロセッサ数です。median と max の間に大きなギャップがある場合は、並列プロセッサ間で負荷に偏りがあることを示します。
ステップと分岐の実経過時間と同時実行度
time = 0 でない場合、各クエリプランステップに追加で2行が出力されます。
step はステップ自体を指します。branch はそのステップを根とする部分木、つまり実行計画内のそのステップと、その下にあるすべてのステップを指します。
Time— そのステップ (step) 、または部分木内のいずれかのステップ (branch) で、少なくとも1つのスレッドが処理を行っていた実時間です。<share>は、その時間がクエリ実行時間に占める割合です。Concurrency— そのステップ (step) または部分木 (branch) が処理されている間に、クエリのいずれかのステップで処理を行っていたスレッドの平均数です。このステップで処理していたスレッドだけには限りません。<m>はクエリが使用できるスレッドの最大数です。入力のヘッダーがすでに同じ場合のUnionなど、プロセッサを持たないステップでは、測定対象となる処理がないため、stepにUnknownと表示されます。branchの値は引き続き表示されます。
Time は、そのステップの処理区間の和集合の長さです。どのスレッドもそのステップで処理を行っていないギャップは含まれません。branch の Time は、部分木内のすべてのステップの処理区間を統合して求めます。
ルートステップの branch は実行計画全体に相当しますが、その割合は通常100%未満です。クエリの概要にある Execution 行には、残りの実行時間の内訳が示されます (上の例のクエリの概要を参照) 。
in steps— 実行計画内のすべてのステップの処理区間の和集合です。これはルートステップのbranchの時間に相当し、割合も同じです。outside steps— 少なくとも1つのスレッドがプロセッサを実行していたものの、そのいずれもこの実行計画のステップには属していなかった時間です。出力先の sink、Resize、変換を行う transform、この実行計画から到達できない実行計画のステップでの処理が該当します。idle— どのスレッドもプロセッサを実行していなかった時間です。executor の起動・停止中や、すべてのスレッドが待機していた時間が該当します。
Time、各ステージの time、Execution の割合は、いずれも同じ値を分母としているため、相互に比較できます。
Concurrency は、その和集合の区間内でクエリの全スレッドが処理を行っていた時間の合計を、和集合の長さで割った値です。ステージ自体のスレッドのみを数える各ステージの parallelism メトリクスとは異なり、クエリのいずれかのステップで処理していたスレッドを数えます。つまり、“このステップ (branch) が処理されている間、クエリ全体ではどの程度処理が行われていたか?“を示します。値が <m> に近ければ、そのステップが処理されている間、クエリは最大限の並列度を維持していたことを意味します。値が 1 に近ければ、その間のクエリ処理は直列化されていたことを意味します。step の場合、処理を行っていた唯一のスレッドはそのステップ自体を処理していたため、そのステップが直列化の発生箇所です。branch の場合、そのスレッドは部分木内のどこかで処理しており、必ずしもそのステップ自体を処理していたわけではありません。直列化されたステップが実際にボトルネックとなるのは、その Time の割合も大きい場合に限られます。
EXPLAIN ESTIMATE
クエリの実行時に、テーブルから読み取られると推定される行数、マーク数、パーツ数を表示します。MergeTree ファミリーのテーブルで使用できます。 例 テーブルを作成します。Query
Query
Response
EXPLAIN WHATIF
仮想的なスキップ索引がSELECT クエリにどの程度の効果をもたらすかを、ディスク上に索引をマテリアライズせずに推定します。CREATE HYPOTHETICAL INDEX で 1 つ以上の候補を定義してから EXPLAIN WHATIF SELECT ... を実行すると、各候補について適用可否、推定読み取りマーク数、推定バイト数、スキップ率を確認できます。
CREATE HYPOTHETICAL PROJECTION で定義した仮説的なプロジェクションも候補になります。通常のプロジェクションの推定では、クエリが読み取るパーツを対象にそのプライマリインデックスをメモリ上に構築し、マテリアライズ済みのプロジェクションと同じ方法で絞り込みを行います。
レポートには、読み取ることになるマーク数と行数、基となるテーブルの読み取りに対する read_ratio、およびオプティマイザがそのプロジェクションを選択するかどうかを示す verdict が示されます。force_optimize_projection = 1 または prefer_optimize_projection = 1 が指定されている場合、オプティマイザは使用可能なプロジェクションであればどれでも使用するため、コストの観点からは選ばれないプロジェクションも chosen (forced) として報告されます。
結果がプロジェクションパーツのレイアウトに依存する場合は、marks_span に範囲が示され、どちらとも判断できない判定は too close to call として報告されます。大きなテーブルでは、推定はグラニュールのサンプルを読み取って行われます (projection_scan_budget_rows を参照)。
集約プロジェクション、WHERE 句、独自のスキップ索引、コミット順または仮想カラムのキー、あるいは格納された _block_number を持つプロジェクション、およびクエリが読み取るカラムをすべてカバーしていないプロジェクションは、not_applicable として報告されます。force_optimize_projection_name と preferred_optimize_projection_name は無視され、force_optimize_projection によってステートメントが失敗することはありません。
構文
projection_scan_budget_rows— プロジェクションの推定が、グラニュールのサンプリングに切り替わる前に読み取ってよい行数です。デフォルト:10000000。0は無制限を意味し、max_rows_to_readでこの値を引き下げることもできます。サンプリングでは少なくとも約 30 個のグラニュールを読み取り、かつパーツごとに 1 つ以上のグラニュールを読み取ります。max_rows_to_readによってこれが許容されない場合、推定はunsupportedになります。empirical—1(デフォルト) では、ベースラインによるプルーニング後に残ったグラニュールに対し、メモリ上で索引を評価してスキップ率 (上限値) を測定します。0では、この処理を行いません。どちらの設定でも、実測で結果が得られない場合 (無効になっている場合や、メモリ上で索引を評価できない場合) は、推定器がカラム STATISTICSを使用します。どちらも利用できない場合は、適用可能かどうかのみを示す要約に切り替えます。
source— 推定値の算出方法を示します。empirical: ベースラインで プルーニングされたグラニュールを対象に、メモリ内で索引を構築し、その索引によってスキップされるグラニュール数を数えます。これは上限値です。制限事項についてはCREATE HYPOTHETICAL INDEXを参照してください。statistical: カラム STATISTICS から導出されます。empirical が無効化されている場合 (empirical = 0) 、または empirical で結果を生成できず、かつ関連するカラムにカラム STATISTICS が定義されている場合に使用されます。applicability_only: 索引は predicate に適用可能ですが、empirical と statistical のいずれでも結果を生成できなかったことを示します (たとえばempirical = 0でカラム STATISTICS が定義されていない場合) 。保守的な上限としてskip_ratio: 0.0%を返します。
empirical_reason— 経験的推定を実行できなかった理由です。empirical_status: unsupportedの場合にのみ表示されます。たとえば、merge_tree_min_rows_for_seekまたはmerge_tree_min_bytes_for_seekがゼロ以外の場合、実際の読み取りではマーク範囲が統合されますが、グラニュールごとのカウントではこれをモデル化しないため、推定はstatisticalまたはapplicability_onlyにフォールバックします。sampled_parts/sampled_marks—<baseline-pruned> / <total in the table>。テーブル全体のうち、PK、partition、既存の索引による 枝刈り を通過した割合、つまり仮想索引への入力となる部分を示します。プロジェクションの場合、sampled_marksは<marks read> / <marks in the parts the query reads>を表し、最初の数値が 2 番目の数値より小さければ、推定にサンプルが使われたことを意味します。est_bytes— 読み取られるバイト数の推定値です。テーブルの平均行サイズから導出されるため概算であり、ストレージや圧縮によって変動します。ベースラインの行はクエリが行を読み取る場合にのみ表示され、候補ごとの行はベースラインのバイト推定値がわかっている場合にのみ表示されます。
WHATIF と SELECT の間にインラインで記述します。SETTINGS キーワードはありません (これは、他の EXPLAIN バリアントでオプションを受け付ける方法と一致しています) 。
テーブルに仮想索引も仮説的なプロジェクションも定義されていない場合、EXPLAIN WHATIF は status: not_applicable を返し、作成を促すヒントを表示します。
結合行 (複数候補)
2 つ以上の候補を経験的に評価した場合、EXPLAIN WHATIF は候補ごとの行の後に、(combined: idx_a, idx_b, ...) という名前のブロックを 1 つ追加します。これは、それらの索引をすべて同時に使用した場合の効果を示します。実際の読み取りでグラニュールが残るのは、すべてのスキップ索引による絞り込みを通過した場合だけです。そのため、結合推定値は各候補で残るグラニュールの積集合に基づきます。したがって、その skip_ratio は最も効果の高い単独候補以上になります。相補的な索引を組み合わせるとさらに多くのグラニュールを除外できますが、冗長な索引を追加してもスキップ率は変わりません。
結合行は候補ごとに残るグラニュールの集合の積集合から作られるため、対象となるのは source: empirical の候補だけです。statistical または applicability_only で推定された候補にはグラニュールごとのデータがないため、対象外です。そのため、結合ブロックは少なくとも 2 つの候補で経験的推定値が得られた場合にのみ表示され、それ以外の場合 (たとえば empirical = 0 の場合) は省略されます。推定に関するフィールドは候補ごとの empirical ブロックと同じですが、elapsed_us は 0 です。結合推定値は新たにスキャンせず、候補ごとのスキャン結果から導出されるためです。合成された (combined: ...) という名前はレポート上のラベルにすぎず、force_data_skipping_indices では使用できません。
経験的推定の例
minmax によって、マーク数は 100 から 1 に絞り込まれます。スキップ率は skip_ratio: 99.0% です。(est_bytes は平均行サイズに基づく推定値のため、正確な値は変動します。)
統計ベースの例
カラム STATISTICSはデフォルトで無効になっています。statistical パスを試すには、まず対象のカラムでこれらを定義し、materialize mutation が完了するまで待ちます:
b < 10 のカラム STATISTICS における選択性 (10000 行中およそ 10 行) に基づくもので、skip_ratio の上限として報告されます。sampled_parts / sampled_marks はなく、データは読み取られていません。
どちらの方法も利用できない場合 (たとえば empirical = 0 で、かつカラム STATISTICS が定義されていない場合) 、推定器は source: applicability_only と保守的な skip_ratio: 0.0% を報告します。
仮説的なプロジェクション
通常のプロジェクションも、主キーとパーティションによる枝刈りを経てクエリが読み取るパーツを対象に、同じ方法で推定されます:
marks と rows は、基となるテーブルの読み取りに占める割合ではなく、プロジェクションを読み取る際に実際にアクセスするマークと行を示します。プロジェクションのグラニュールには、基となるテーブルのグラニュールとは異なる行が含まれるためです。read_ratio はプロジェクションのマーク数を基となるテーブルのマーク数で割った値で、0.02x は読み取り量が 50 分の 1、15x は 15 倍であることを意味します。verdict はオプティマイザ自身の判断基準に従います。プロジェクションのマーク数が基となるテーブルより少ないか、同数でもプロジェクションがクエリの ORDER BY に対応している場合に選択されるため、候補が applicable でも選択されないことがあります。
EXPLAIN TABLE OVERRIDE
テーブル関数を介してアクセスするテーブルのスキーマに対して、テーブルオーバーライドを適用した結果を表示します。 また、いくつかの検証も行い、オーバーライドによって何らかの問題が発生する場合は例外をスローします。 例 次のようなリモート MySQL テーブルがあるとします。Query
Query
Response
検証は完全ではないため、クエリが成功しても、そのオーバーライドが問題を引き起こさないことは保証されません。