> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-trino-dialect.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> EXPLAIN に関するドキュメント

# EXPLAIN ステートメント

ステートメントの実行計画を表示します。

<div class="vimeo-container">
  <Frame>
    <iframe
      src="//www.youtube.com/embed/hP6G2Nlz_cA"
      frameborder="0"
      allow="autoplay;
fullscreen;
picture-in-picture"
      allowfullscreen
    />
  </Frame>
</div>

構文:

```sql theme={null}
EXPLAIN [AST | SYNTAX | QUERY TREE | PLAN | PIPELINE | ANALYZE | ESTIMATE | TABLE OVERRIDE | WHATIF] [setting = value, ...]
    [
      SELECT ... |
      tableFunction(...) [COLUMNS (...)] [ORDER BY ...] [PARTITION BY ...] [PRIMARY KEY] [SAMPLE BY ...] [TTL ...]
    ]
    [FORMAT ...]
```

例:

```sql theme={null}
EXPLAIN SELECT sum(number) FROM numbers(10) UNION ALL SELECT sum(number) FROM numbers(10) ORDER BY sum(number) ASC FORMAT TSV;
```

```sql theme={null}
Output: sum(number)

Union
├──Aggregating
│  │  Keys:
│  │  Aggregates: sum(number)
│  │  Skip merging: 0
│  └──ReadFromSystemNumbers
│        Output: number
└──Sorting (Sorting for ORDER BY)
   │  Sort description: sum(number) ASC
   └──Aggregating
      │  Keys:
      │  Aggregates: sum(number)
      │  Skip merging: 0
      └──ReadFromSystemNumbers
            Output: number
```

<div id="explain-types">
  ## EXPLAIN の種類
</div>

* `AST` — 抽象構文木。
* `SYNTAX` — AST レベルでの最適化後のクエリテキスト。
* `QUERY TREE` — クエリツリー レベルでの最適化後のクエリツリー。
* `PLAN` — クエリ実行プラン。
* `PIPELINE` — クエリ実行パイプライン。
* `ANALYZE` — クエリを実行し、計測されたランタイムメトリクスを実行計画に注釈として付加します。
* `ESTIMATE` — クエリの処理中にテーブルから読み取ると見積もられる行数、マーク数、パーツ数。
* `TABLE OVERRIDE` — テーブル関数のスキーマに対するテーブルオーバーライドの検証済み結果。

<div id="explain-ast">
  ### EXPLAIN AST
</div>

クエリASTをダンプします。`SELECT` だけでなく、あらゆる種類のクエリをサポートします。

設定:

* `graph` – [DOT](https://en.wikipedia.org/wiki/DOT_\(graph_description_language\)) グラフ記述言語で記述されたグラフとして AST を出力します。デフォルト: 0。

例:

```sql theme={null}
EXPLAIN AST SELECT 1;
```

```sql theme={null}
SelectWithUnionQuery (children 1)
 ExpressionList (children 1)
  SelectQuery (children 1)
   ExpressionList (children 1)
    Literal UInt64_1
```

```sql theme={null}
EXPLAIN AST ALTER TABLE t1 DELETE WHERE date = today();
```

```sql theme={null}
  explain
  AlterQuery  t1 (children 1)
   ExpressionList (children 1)
    AlterCommand 27 (children 1)
     Function equals (children 1)
      ExpressionList (children 2)
       Identifier date
       Function today (children 1)
        ExpressionList
```

<div id="explain-syntax">
  ### EXPLAIN SYNTAX
</div>

構文解析後のクエリの抽象構文木 (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` より前の任意のバージョンに設定します。

例:

```sql title="Query" theme={null}
EXPLAIN SYNTAX SELECT * FROM system.numbers AS a, system.numbers AS b, system.numbers AS c WHERE a.number = b.number AND b.number = c.number;
```

```sql title="Response" theme={null}
SELECT *
FROM system.numbers AS a, system.numbers AS b, system.numbers AS c
WHERE (a.number = b.number) AND (b.number = c.number)
```

`run_query_tree_passes` を指定した場合:

```sql title="Query" theme={null}
EXPLAIN SYNTAX run_query_tree_passes = 1 SELECT * FROM system.numbers AS a, system.numbers AS b, system.numbers AS c WHERE a.number = b.number AND b.number = c.number;
```

```sql title="Response" theme={null}
SELECT
    __table1.number AS `a.number`,
    __table2.number AS `b.number`,
    __table3.number AS `c.number`
FROM system.numbers AS __table1
ALL INNER JOIN system.numbers AS __table2 ON __table1.number = __table2.number
ALL INNER JOIN system.numbers AS __table3 ON __table2.number = __table3.number
```

<div id="explain-query-tree">
  ### EXPLAIN QUERY TREE
</div>

設定:

* `run_passes` — クエリツリーをダンプする前に、すべてのクエリツリーパスを実行します。デフォルト: `1`。
* `dump_passes` — クエリツリーをダンプする前に、使用されるパスの情報をダンプします。デフォルト: `0`。
* `passes` — 実行するパスの数を指定します。`-1` に設定すると、すべてのパスを実行します。デフォルト: `-1`。
* `dump_tree` — クエリツリーを表示します。デフォルト: `1`。
* `dump_ast` — クエリツリーから生成されたクエリ AST を表示します。デフォルト: `0`。

例:

```sql theme={null}
EXPLAIN QUERY TREE SELECT id, value FROM test_table;
```

```sql theme={null}
QUERY id: 0
  PROJECTION COLUMNS
    id UInt64
    value String
  PROJECTION
    LIST id: 1, nodes: 2
      COLUMN id: 2, column_name: id, result_type: UInt64, source_id: 3
      COLUMN id: 4, column_name: value, result_type: String, source_id: 3
  JOIN TREE
    TABLE id: 3, table_name: default.test_table
```

<div id="explain-plan">
  ### EXPLAIN PLAN
</div>

クエリプランのステップを出力します。

設定:

* `optimize` — プランを表示する前に、クエリプランの最適化を適用するかどうかを制御します。デフォルト: 1。
* `header` — ステップの出力ヘッダーを表示します。デフォルト: 0。
* `description` — ステップの説明を表示します。デフォルト: 1。
* `indexes` — 使用された索引、フィルタリングされたパーツ数、および適用された各索引についてフィルタリングされたグラニュール数を表示します。デフォルト: 0。[MergeTree](/ja/reference/engines/table-engines/mergetree-family/mergetree) テーブルでサポートされています。ClickHouse >= v25.9 以降、このステートメントが適切な出力を示すのは、`SETTINGS use_query_condition_cache = 0, use_skip_indexes_on_data_read = 0` とともに使用した場合のみです。
* `projections` — 解析されたすべてのプロジェクションと、プロジェクションの主キー条件に基づくパーツレベルのフィルタリングへの影響を表示します。各プロジェクションについて、このセクションには、プロジェクションの主キーを使って評価されたパーツ数、行数、マーク数、範囲数などの統計が含まれます。また、このフィルタリングにより、プロジェクション自体を読み取ることなくスキップされた data parts の数も表示します。プロジェクションが実際に読み取りに使用されたのか、それともフィルタリングのために解析されただけなのかは、`description` フィールドで判別できます。デフォルト: 0。[MergeTree](/ja/reference/engines/table-engines/mergetree-family/mergetree) テーブルでサポートされています。
* `actions` — ステップの actions に関する詳細情報を表示します。デフォルト: 1。
* `sorting` — ソート済みの出力を生成する各プランステップについて、ソートの説明を表示します。デフォルト: 0。
* `keep_logical_steps` — joins について、物理的な join 実装に変換せずに、論理プランステップを保持します。デフォルト: 0。
* `json` — クエリプランのステップを [JSON](/ja/reference/formats/JSON/JSON) フォーマットの 1 行として出力します。デフォルト: 0。不要なエスケープを避けるため、[TabSeparatedRaw (TSVRaw)](/ja/reference/formats/TabSeparated/TabSeparatedRaw) フォーマットの使用を推奨します。
* `input_headers` — ステップの入力ヘッダーを表示します。デフォルト: 0。主に、入力ヘッダーと出力ヘッダーの不一致に関する問題をデバッグする開発者にのみ有用です。
* `column_structure` — ヘッダー内のカラム構造を、名前と型に加えて表示します。デフォルト: 0。主に、入力ヘッダーと出力ヘッダーの不一致に関する問題をデバッグする開発者にのみ有用です。
* `distributed` — 分散テーブルまたは並列レプリカについて、リモートノードで実行されるクエリプランを表示します。`json` と同時にはサポートされません。デフォルト: 0。
* `compact` — 有効にすると、プランから expression ステップと詳細な action 情報 (入力、関数、別名、出力位置) を非表示にします。`actions = 1` の場合にのみ効果があります。デフォルト: 1。
* `pretty` — インデントの代わりに罫線文字 (├──、└──、│) を使ってプランツリーを表示し、階層構造を視覚化します。さらに、join ステップのプロパティもインラインで整形して表示します。デフォルト: 1。

<Note>
  デフォルトでは、`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` を手動で設定してください。
</Note>

例:

```sql theme={null}
EXPLAIN SELECT sum(number) FROM numbers(10) GROUP BY number % 4  LIMIT 1;
```

```sql theme={null}
Output: sum(number)

Limit (preliminary LIMIT)
│  Limit 1
│  Offset 0
└──Aggregating
   │  Keys: number MOD 4
   │  Aggregates: sum(number)
   │  Skip merging: 0
   └──ReadFromSystemNumbers
         Output: number
```

<Note>
  Step およびクエリのコスト見積もりはサポートされていません。
</Note>

`json = 1` の場合、クエリプランは JSON フォーマットで表されます。各ノードは辞書で、常に `Node Type`、`Node Id`、`Plans` のキーを持ちます。`Node Type` はステップ名を表す文字列で、`Node Id` は一意のステップ識別子です (数値の接尾辞が付いたステップ名。例: `Union_10`) 。`Plans` は子ステップの説明を含む配列です。その他の任意のキーは、ノードの種類や設定に応じて追加されることがあります。

例:

```sql theme={null}
EXPLAIN json = 1, description = 0 SELECT 1 UNION ALL SELECT 2 FORMAT TSVRaw;
```

```json theme={null}
[
  {
    "Plan": {
      "Node Type": "Union",
      "Node Id": "Union_10",
      "Plans": [
        {
          "Node Type": "Expression",
          "Node Id": "Expression_13",
          "Plans": [
            {
              "Node Type": "ReadFromStorage",
              "Node Id": "ReadFromStorage_0"
            }
          ]
        },
        {
          "Node Type": "Expression",
          "Node Id": "Expression_16",
          "Plans": [
            {
              "Node Type": "ReadFromStorage",
              "Node Id": "ReadFromStorage_4"
            }
          ]
        }
      ]
    }
  }
]
```

`description` = 1 の場合、`Description` キーがステップに追加されます。

```json theme={null}
{
  "Node Type": "ReadFromStorage",
  "Description": "SystemOne"
}
```

`header` = 1 の場合、`Header` キーがカラムの配列としてステップに追加されます。

例:

```sql theme={null}
EXPLAIN json = 1, description = 0, header = 1 SELECT 1, 2 + dummy;
```

```json theme={null}
[
  {
    "Plan": {
      "Node Type": "Expression",
      "Node Id": "Expression_5",
      "Header": [
        {
          "Name": "1",
          "Type": "UInt8"
        },
        {
          "Name": "plus(2, dummy)",
          "Type": "UInt16"
        }
      ],
      "Plans": [
        {
          "Node Type": "ReadFromStorage",
          "Node Id": "ReadFromStorage_0",
          "Header": [
            {
              "Name": "dummy",
              "Type": "UInt8"
            }
          ]
        }
      ]
    }
  }
]
```

`indexes` = 1 の場合、`Indexes` キーが追加されます。これには、使用された索引の配列が含まれます。各索引は JSON で記述され、`Type` キー (文字列 `Partition Min-Max`、`Partition`、`Statistics`、`PrimaryKey` または `Skip`) と、必要に応じて以下のキーを持ちます。

* `Name` — 索引名 (現在は `Skip` 索引でのみ使用) 。
* `Keys` — 索引で使用されるカラムの配列。
* `Condition` — 使用された条件。
* `Description` — 索引の説明 (現在は `Skip` 索引でのみ使用) 。
* `Parts` — 索引の適用後/適用前のパーツ数。
* `Granules` — 索引の適用後/適用前のグラニュール数。
* `Ranges` — 索引の適用後のグラニュール範囲数。

例:

```json theme={null}
"Node Type": "ReadFromMergeTree",
"Indexes": [
  {
    "Type": "Partition Min-Max",
    "Keys": ["y"],
    "Condition": "(y in [1, +inf))",
    "Parts": 4/5,
    "Granules": 11/12
  },
  {
    "Type": "Partition",
    "Keys": ["y", "bitAnd(z, 3)"],
    "Condition": "and((bitAnd(z, 3) not in [1, 1]), and((y in [1, +inf)), (bitAnd(z, 3) not in [1, 1])))",
    "Parts": 3/4,
    "Granules": 10/11
  },
  {
    "Type": "PrimaryKey",
    "Keys": ["x", "y"],
    "Condition": "and((x in [11, +inf)), (y in [1, +inf)))",
    "Parts": 2/3,
    "Granules": 6/10,
    "Search Algorithm": "generic exclusion search"
  },
  {
    "Type": "Skip",
    "Name": "t_minmax",
    "Description": "minmax GRANULARITY 2",
    "Parts": 1/2,
    "Granules": 2/6
  },
  {
    "Type": "Skip",
    "Name": "t_set",
    "Description": "set GRANULARITY 2",
    "": 1/1,
    "Granules": 1/2
  }
]
```

`projections` = 1 を指定すると、`Projections` キーが追加されます。これには、分析されたプロジェクションの配列が含まれます。各プロジェクションは、以下のキーを持つ JSON として記述されます：

* `Name` — プロジェクション名。
* `Condition` — プロジェクションで使用された主キー条件。
* `Description` — プロジェクションの使用方法の説明 (例: パーツレベルのフィルタリング) 。
* `Selected Parts` — プロジェクションによって選択されたパーツ数。
* `Selected Marks` — 選択されたマーク数。
* `Selected Ranges` — 選択された範囲数。
* `Selected Rows` — 選択された行数。
* `Filtered Parts` — パーツレベルのフィルタリングによってスキップされたパーツ数。

例：

```json theme={null}
"Node Type": "ReadFromMergeTree",
"Projections": [
  {
    "Name": "region_proj",
    "Description": "Projection has been analyzed and is used for part-level filtering",
    "Condition": "(region in ['us_west', 'us_west'])",
    "Search Algorithm": "binary search",
    "Selected Parts": 3,
    "Selected Marks": 3,
    "Selected Ranges": 3,
    "Selected Rows": 3,
    "Filtered Parts": 2
  },
  {
    "Name": "user_id_proj",
    "Description": "Projection has been analyzed and is used for part-level filtering",
    "Condition": "(user_id in [107, 107])",
    "Search Algorithm": "binary search",
    "Selected Parts": 1,
    "Selected Marks": 1,
    "Selected Ranges": 1,
    "Selected Rows": 1,
    "Filtered Parts": 2
  }
]
```

`actions` = 1 の場合、追加されるキーはステップの種類によって異なります。

例：

```sql theme={null}
EXPLAIN json = 1, actions = 1, description = 0 SELECT 1 FORMAT TSVRaw;
```

```json theme={null}
[
  {
    "Plan": {
      "Node Type": "Expression",
      "Node Id": "Expression_5",
      "Expression": {
        "Inputs": [
          {
            "Name": "dummy",
            "Type": "UInt8"
          }
        ],
        "Actions": [
          {
            "Node Type": "INPUT",
            "Result Type": "UInt8",
            "Result Name": "dummy",
            "Arguments": [0],
            "Removed Arguments": [0],
            "Result": 0
          },
          {
            "Node Type": "COLUMN",
            "Result Type": "UInt8",
            "Result Name": "1",
            "Column": "Const(UInt8)",
            "Arguments": [],
            "Removed Arguments": [],
            "Result": 1
          }
        ],
        "Outputs": [
          {
            "Name": "1",
            "Type": "UInt8"
          }
        ],
        "Positions": [1]
      },
      "Plans": [
        {
          "Node Type": "ReadFromStorage",
          "Node Id": "ReadFromStorage_0"
        }
      ]
    }
  }
]
```

`compact = 0` かつ `actions = 1` を指定すると、`Expression` ステップとともに式に関する詳細情報を確認できます：

```sql theme={null}
EXPLAIN actions = 1, compact = 0 SELECT sum(number) FROM numbers(10) GROUP BY number % 4;
```

```text theme={null}
Output: sum(number)

Expression ((Project names + Projection))
│  Actions: INPUT : 0 -> sum(__table1.number) UInt64 : 0
│           INPUT :: 1 -> modulo(__table1.number, 4_UInt8) UInt8 : 1
│           ALIAS sum(__table1.number) :: 0 -> sum(number) UInt64 : 2
│  Positions: 2
└──Aggregating
   │  Keys: number MOD 4
   │  Aggregates: sum(number)
   │  Skip merging: 0
   └──Expression ((Before GROUP BY + Change column names to column identifiers))
      │  Actions: INPUT : 0 -> number UInt64 : 0
      │           COLUMN Const(UInt8) -> 4_UInt8 UInt8 : 1
      │           ALIAS number :: 0 -> __table1.number UInt64 : 2
      │           FUNCTION modulo(__table1.number : 2, 4_UInt8 :: 1) -> modulo(__table1.number, 4_UInt8) UInt8 : 0
      │  Positions: 0 2
      └──ReadFromSystemNumbers
            Output: number
```

`distributed` = 1 を指定すると、出力にはローカルのクエリプランだけでなく、リモートノードで実行されるクエリプランも含まれます。これは、分散クエリの分析やデバッグに役立ちます。

<Note>
  `distributed` は、`pretty` 出力ではリモート分片のプランがプランツリーに統合されないため、`legacy` (非`pretty`) 形式でのみ表示されます。このため、`distributed` を有効にすると、`explain_query_plan_default` の値に関係なく、`pretty` のデフォルト設定 (`actions`、`compact`、`pretty`) は自動的に無効になります。なお、`actions=1` は手動で設定できます。また、`distributed` オプションは `json` と併用できません。
</Note>

分散テーブルを使用した例:

```sql theme={null}
EXPLAIN distributed=1 SELECT * FROM remote('127.0.0.{1,2}', numbers(2)) WHERE number = 1;
```

```sql theme={null}
Union
  Expression ((Project names + (Projection + (Change column names to column identifiers + (Project names + Projection)))))
    Filter ((WHERE + Change column names to column identifiers))
      ReadFromSystemNumbers
  Expression ((Project names + (Projection + Change column names to column identifiers)))
    ReadFromRemote (Read from remote replica)
      Expression ((Project names + Projection))
        Filter ((WHERE + Change column names to column identifiers))
          ReadFromSystemNumbers
```

並列レプリカを使用した例：

```sql theme={null}
SET enable_parallel_replicas = 2, max_parallel_replicas = 2, cluster_for_parallel_replicas = 'default';

EXPLAIN distributed=1 SELECT sum(number) FROM test_table GROUP BY number % 4;
```

```sql theme={null}
Expression ((Project names + Projection))
  MergingAggregated
    Union
      Aggregating
        Expression ((Before GROUP BY + Change column names to column identifiers))
          ReadFromMergeTree (default.test_table)
      ReadFromRemoteParallelReplicas
        BlocksMarshalling
          Aggregating
            Expression ((Before GROUP BY + Change column names to column identifiers))
              ReadFromMergeTree (default.test_table)
```

どちらの例でも、クエリプランにはローカルおよびリモートのステップを含む完全な実行フローが示されています。

`pretty` = 1 を指定すると、プランツリーはインデントの代わりに罫線文字で表示され、主要なステップの追加情報も表示されます：

* **クエリ出力カラム** はプランの先頭に表示されます。
* フィルタ、集約キー、ソートの説明、ウィンドウ関数内の **式** は、人が読める SQL 風の表記で表示されます (例: `greater(plus(a, 1), 5)` ではなく `a + 1 > 5`) 。わかりやすさのため、内部カラム識別子のプレフィックス (`__table1.` など) は削除されます。
* **ソースステップ** (`ReadFromMergeTree` など) には、その出力カラムが表示されます。
* **フィルタステップ** には、SQL 表記のフィルタ条件が表示されます。ランタイム join フィルタが存在する場合は、それらは別個に表示されます。
* **集約ステップ** には、キーと、引数付きの集約関数 (例: `sum(c)`、`count()`) が表示されます。
* タプルリテラルの **IN set** にはその値が表示され (大きな set の場合は切り詰められます) 、サブクエリベースの set には `subquery1`、`subquery2` などのラベルが付き、`Set` engine tables 由来の set にはテーブル名が表示されます。
* **join ステップ** には、数学的記法を用いた join 関係、推定結果行数、
  およびどの出力カラムが左側と右側のどちらに由来するかが表示されます。異なる join タイプを
  表すために、次の記号が使用されます：

| Symbol                 | Join Type       |
| ---------------------- | --------------- |
| `⋈`                    | Inner Join      |
| `⟕`                    | Left Join       |
| `⟖`                    | Right Join      |
| `⟗`                    | Full Join       |
| `⋉`                    | Left Semi Join  |
| `⋊`                    | Right Semi Join |
| `⋉` with strikethrough | Left Anti Join  |
| `⋊` with strikethrough | Right Anti Join |
| `×`                    | Cross Join      |

たとえば、`t1 ⟕ t2` はテーブル `t1` と `t2` の left join を意味します。
テーブル名の後の角括弧内の数値 (例: `t1[100]`) は、テーブル統計が利用可能な場合の
推定行数を示します。

`pretty` オプションは `compact = 1` と組み合わせると効果的で、`Expression` ステップと詳細な action 情報が非表示になるため、プランが読みやすくなります。

JOINを使った詳しい例:

```sql theme={null}
CREATE TABLE t1 (id UInt64, value String) ENGINE = MergeTree ORDER BY id;
CREATE TABLE t2 (id UInt64, value String) ENGINE = MergeTree ORDER BY id;
INSERT INTO t1 SELECT number, toString(number) FROM numbers(100);
INSERT INTO t2 SELECT number, toString(number) FROM numbers(100);

EXPLAIN actions = 1, compact = 1, pretty = 1
SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id FORMAT Raw;
```

```text theme={null}
Output: id, value, id, value

Join (JOIN FillRightFirst)
│  t1[100] ⋈ t2[100]
│  Type: inner | Strictness: all | Algorithm: SpillingHashJoin(HashJoin)
│  Result rows: 100
│  Join conditions: id = id
│  Output:
│    Left:  id, value
│    Right: id, value
├──ReadFromMergeTree (default.t1)
│     Read type: Default
│     Parts: 1 | Granules: 1
│     Output: id, value
│     Runtime filters: RF1(id, id from default.t2)
└──BuildRuntimeFilter (Build runtime join filter on id)
   │  Filter id: RF1
   │  Source table: default.t2
   └──ReadFromMergeTree (default.t2)
         Read type: Default
         Parts: 1 | Granules: 1
         Output: id, value
```

<div id="explain-pipeline">
  ### EXPLAIN PIPELINE
</div>

設定:

* `header` — 各出力ポートのヘッダーを表示します。デフォルト: 0。
* `graph` — [DOT](https://en.wikipedia.org/wiki/DOT_\(graph_description_language\)) グラフ記述言語で記述されたグラフを表示します。デフォルト: 0。
* `compact` — `graph` 設定が有効な場合、compact モードでグラフを表示します。デフォルト: 1。
* `compact_repeated_processor_chains` — テキスト出力で、隣接して繰り返されるプロセッサチェーンを、チェーンを 1 つだけ表示して繰り返し回数を付けることでコンパクトにします。これにより、たとえば JOIN で同じチェーンが何度も現れる場合に、並列パイプラインが読みやすくなります。グラフ出力には影響しません。デフォルト: 0。

```text theme={null}
Resize 16 → 1
  FillingRightJoinSide          │
    SimpleSquashingTransform    │ × 16
      Resize 1 → 16
```

`compact=0` かつ `graph=1` の場合、プロセッサ名には一意のプロセッサ識別子を示す追加の接尾辞が含まれます。

例:

```sql theme={null}
EXPLAIN PIPELINE SELECT sum(number) FROM numbers_mt(100000) GROUP BY number % 4;
```

```sql theme={null}
(Union)
(Expression)
ExpressionTransform
  (Expression)
  ExpressionTransform
    (Aggregating)
    Resize 2 → 1
      AggregatingTransform × 2
        (Expression)
        ExpressionTransform × 2
          (SettingQuotaAndLimits)
            (ReadFromStorage)
            NumbersRange × 2 0 → 1
```

<div id="explain-analyze">
  ### EXPLAIN ANALYZE
</div>

`EXPLAIN ANALYZE` は実際にクエリを実行し、結果の行を破棄したうえで、各ステップに実行時に実際に何が起きたかを注記として付けた、`EXPLAIN PLAN` と同じプランツリーを出力します。

設定:

`EXPLAIN ANALYZE` では、`EXPLAIN PLAN` と同じ表示オプションを使用できます ([EXPLAIN PLAN](#explain-plan) セクションを参照) 。

* `header` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。
* `description` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。
* `projections` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。
* `sorting` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。
* `input_headers` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。
* `column_structure` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。
* `actions` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。デフォルト: 1。
* `indexes` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。デフォルト: 1。
* `compact` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。デフォルト: 1。
* `pretty` — [EXPLAIN PLAN](#explain-plan) セクションを参照してください。デフォルト: 1。
* `processors` — `EXPLAIN ANALYZE` では、各ステージについて、プロセッサごとの経過時間分布 (`min`、`median`、`max`、`sum`) を示す追加の行を出力します。並列プロセッサ間の負荷の偏りを見つけるのに役立ちます。デフォルト: 0。
* `matches` — `EXPLAIN ANALYZE` では、結合による出力だけではこれらの数値を導出できない場合に、`matched`、`match rate`、`fanout` メトリクスに必要な追加の記録処理を join ステップで行います。導出できる場合は、このオプションなしで報告されます。[join ステップ](#explain-analyze-join-steps)を参照してください。デフォルト: 0。

<Note>
  `EXPLAIN ANALYZE` はラップされたクエリを実際に実行するため、いくつかの点で、そのクエリと同じように動作し、実行しない `EXPLAIN` 形式とは異なります。

  * **クォータと制限。** クエリを直接実行した場合と同じ [quotas](/ja/concepts/features/configuration/server-config/quotas)
    に対してカウントされ、同じ [limits](/ja/concepts/features/configuration/settings/query-complexity)
    (たとえば `query_selects`、`read_rows`) の対象にもなります。プランニング中はクォータの対象外となるテーブル
    (`system.one` など) についてはカウントされません。
  * **失敗したトランザクション。** すでに失敗している [transaction](/ja/concepts/features/operations/insert/transactions)
    (`ROLLED_BACK`) 内では、通常の `SELECT` と同様に `INVALID_TRANSACTION` で拒否されます。
    先に `ROLLBACK` を実行してください。
  * **ストリーミング読み取り。** ストリーミング (`FROM ... STREAM`) 読み取りに対しては、
    そのような読み取りは完了しないため、`NOT_IMPLEMENTED` で拒否されます。
  * **分散クエリ。** [distributed](/ja/reference/engines/table-engines/special/distributed) モードで実行される
    クエリではサポートされていません。
</Note>

例:

```sql theme={null}
EXPLAIN ANALYZE SELECT number % 10 AS k, count() FROM numbers_mt(1000000) GROUP BY k;
```

```text theme={null}
Query summary:
  Time:        10.72 ms (planning 6.45 ms · execution 4.26 ms)
  Read:        1.00 million rows, 8.00 MB (234.49 million rows/s., 1.88 GB/s.)
  Peak memory: 28.98 KiB

Output: number MOD 10, count()

Expression ((Project names + Projection))
│  I/O: rows 10 → 10 · 90 B → 90 B
│    time 21.82 us (0.5%) · parallelism 0.98/1
└──Aggregating
   │  Keys: number MOD 10
   │  Aggregates: count()
   │  Skip merging: 0
   │  I/O: rows 1.00 million → 10 (0.00%) · 1.00 MB → 90 B
   │    Stage (partial aggregation): time 868.45 us (20.4%) · parallelism 3.80/15
   │    Stage (final aggregation): time 445.27 us (10.4%) · parallelism 1.11/16
   └──Expression ((Before GROUP BY + Change column names to column identifiers))
      │  I/O: rows 1.00 million → 1.00 million · 8.00 MB → 1.00 MB
      │    time 677.07 us (15.9%) · parallelism 4.31/15
      └──ReadFromSystemNumbers
            Output: number
            I/O: rows 0 → 1.00 million · 0 B → 8.00 MB
              time 993.94 us (23.3%) · parallelism 7.52/15
```

出力を見てみましょう。まずはヘッダーを見てみましょう。

```txt theme={null}
   Query summary:
     Time:        <total> (planning <planning> · execution <execution>)
     Read:        <rows> rows, <bytes> (<rows/s>, <bytes/s>)
     Peak memory: <peak>
```

* `Time` — 合計時間です。planning (つまり、plan の作成 + plan の最適化 + パイプラインの構築) フェーズと execution (パイプラインの実行) フェーズに分けて表示されます。
* `Read` — テーブルから読み取られた行数と非圧縮バイト数、および throughput です。これは通常のクエリのフッターで "Processed" として報告される数値と同じです。
* `Peak memory` — クエリが使用したピークメモリです。

次に、クエリプランに表示される新しい行を見ていきましょう。

```txt theme={null}
I/O: rows <in> → <out> (<selectivity>%) · <bytes_in> → <bytes_out>
  [Stage (<stage>): ]time <t> (<share>%) · parallelism <avg>/<max>
```

行数とバイト数は、ステップ全体について一度だけ報告されます (`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)` が表示されます。

<Note>
  ClickHouse は、プランステップ内のタスク実行だけでなく、プランステップ自体の実行も並列化します。`parallelism` メトリクスが反映するのは、このステップの処理だけです。他のステップも同時に実行されることがあるため、この数値から、このステップの並列度をクエリ全体と比較することはできません。
</Note>

<Note>
  `parallelism` の最大値は、次の 2 つのうち小さい方として計算されます。

  1. プランステップ内のタスク総数
  2. `max_threads` で設定されたクエリ処理スレッドの最大数
</Note>

<div id="explain-analyze-join-steps">
  #### Join ステップ
</div>

join ステップでは、`EXPLAIN ANALYZE` は各側の*参加*行 (`Left` と `Right`) を出力し、その後に join の実装固有の行を出力します。`Left` と `Right` は、論理的な SQL の左右に対応します。ほとんどの場合、`Left` は join のプローブ側、`Right` はビルド側にもなります。ただし、join の実行中に swap が発生する可能性があるため、常にそうとは限りません。[`join_algorithm`](/ja/reference/settings/session-settings/join#join_algorithm) のすべての値 (`hash`、`parallel_hash`、`grace_hash`、`partial_merge`、`full_sorting_merge`、`parallel_full_sorting_merge`、`direct`) に対応しています。また、この設定では選択できない 2 つの実装、すなわち `CROSS` または `COMMA` join、キーの等価条件を含まない `ON` 句、および [`Join`](/ja/reference/engines/table-engines/special/join) テーブルエンジンも対象です。ほとんどの実装では両側が報告されますが、マテリアライズする側のみを報告するものもあります (たとえば、`direct` は `Left:` のみを出力します) 。

各側の行は同じ形式です。

```txt theme={null}
Left:  rows <left_rows>  · matched <matched_left_rows>  · match rate <match_rate>% · fanout <fanout>
Right: rows <right_rows> · matched <matched_right_rows> · match rate <match_rate>% · fanout <fanout>
```

各側について、`EXPLAIN ANALYZE` は以下を報告します。

* `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` として報告されます。

<div id="explain-analyze-fanout">
  #### ファンアウト
</div>

`fanout` は行数の増加倍率を示します。

```txt theme={null}
matched output rows = <output_rows> - <NULL-padded rows of both sides>
fanout              = <matched output rows> / <matched_rows of that side>
```

外部結合では、相手が見つからなかった保持側の各行に対して、`NULL` で埋められた出力行が 1 行生成されます。これらの行は比率を薄めないよう差し引かれます。このような行が存在するのは保持側のみです。`RIGHT` と `FULL` では右側、`LEFT` と `FULL` では左側になります。

* `fanout = 0` — 一致した行からは出力行がまったく生成されません。これは `ANTI` join の動作であり、相手が見つからなかった行のみを出力します。
* `fanout = 1` — 明確な 1:1 join です。一致した各行から、ちょうど 1 行の出力行が生成されます。
* `fanout > 1` — 1:N join です。もう一方の側の重複キーによって行数が増加しました。両側で同時に大きな値になる場合は、意図しない Cartesian 的な行数の急増を示します。

<div id="explain-analyze-matches">
  #### 数値に `matches = 1` が必要な場合
</div>

これらの数値の大半は、結合がいずれにせよ構築するデータから得られるため、通常の `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` 種類では何も必要ありません。

<Note>
  追加の追跡処理にはコストがかかり、計測精度に影響します。そのため、このオプションはデフォルトで無効になっています。処理はプローブループ内で実行され、出力行数に応じて増加します。左行と右行が相手側で正確に何件一致したかを知る必要がある場合は、`matches = 1` を使用してください。
</Note>

`matches = 1` を指定しても、すべての組み合わせで収集できるようになるわけではありません。結合がどちらの側を報告できるかは、その結合がいずれにせよ実行する必要がある処理によるため、種類や厳密性だけでなくアルゴリズムにも依存します。

**Hash ファミリー。** `hash`、`parallel_hash`、`grace_hash` は常に同じ結果になります。

| Join                                             | `matched` 左 | `matched` 右 |
| ------------------------------------------------ | ----------- | ----------- |
| `ALL INNER`, `ALL LEFT`, `ALL RIGHT`, `ALL FULL` | はい          | はい          |
| `SEMI LEFT`, `ANTI LEFT`                         | はい          | いいえ         |
| `ANY RIGHT`, `ANTI RIGHT`                        | いいえ         | はい          |
| `ASOF` (inner)                                   | はい          | いいえ         |
| `SEMI RIGHT`                                     | いいえ         | いいえ         |
| `ANY INNER`, `ANY LEFT`, `ASOF LEFT`             | いいえ         | いいえ         |

結合がハッシュテーブル内でキーごとに 1 行だけを保持する場合、右側は収集できません。これは `ANY`、`SEMI`、`ANTI` 結合で行われます。重複する右行は保存されないため、カウントできません。別の左行によってすでに相手が確保されている左行の出力を結合が抑制する場合、左側は収集できません。この場合、出力される行数は一致した行数より少なくなります。

[`any_join_distinct_right_table_keys`](/ja/reference/settings/session-settings/other#any_join_distinct_right_table_keys) を有効にすると、`ANY` は以前の `RightAny` セマンティクスに切り替わります。このセマンティクスでは左行ごとに 1 行が出力されるため、両方のカウントが保持されます。その場合、`ANY RIGHT` と `ANY FULL` は**両方**の側を報告し、`ANY INNER` は `SEMI LEFT` に書き換えられます。

[`Join`](/ja/reference/engines/table-engines/special/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`。** [前述](#explain-analyze-join-algorithm-lines)のとおり、どちらの側も報告されません。

両方のアルゴリズムが数値を報告する場合、その値は一致します。マージアルゴリズムは単により多くの情報を持っているだけで、何を一致とみなすかについて見解が異なるわけではありません。

<div id="explain-analyze-join-algorithm-lines">
  #### アルゴリズム固有の行
</div>

各JOIN実装がこれに加えて出力する行を見てみましょう。

`hash` および `parallel_hash` JOIN、ならびに `Join` テーブルエンジンでは、`Hash table:` 行に右テーブルから構築されたハッシュテーブルの情報が表示されます。

```txt theme={null}
Hash table: unique keys <unique_keys> · memory <peak_memory>
```

* `unique keys <unique_keys>` — ビルドフェーズ中にハッシュテーブルに格納された一意のキーの数。
* `memory <peak_memory>` — ビルドフェーズ中にハッシュテーブルが使用したピークメモリ。

`grace_hash` join では、`Hash table:` 行に、join がメモリ制限にどのように適応したかも表示されます。また、`Spill:` 行には、データがディスクにスピルされたかどうかが表示されます。

```txt theme={null}
Hash table: unique keys <unique_keys> · memory <peak_memory> · buckets <buckets> · rehashes <rehashes>
Spill: yes · left spilled <left_spilled_bytes> · right spilled <right_spilled_bytes>
```

* `buckets <buckets>` — 実行終了時点で Grace Hash Join に含まれるバケット数です。常に `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)` 行に表示されます。

```txt theme={null}
Right: rows <right_rows> · matched <matched_right_rows> · size <right_size> · blocks <right_blocks> · storage <in-memory|external> · match rate <match_rate>% · fanout <fanout>
  Stage (build): time <t> (<share>%) · parallelism <avg>/<max> · sort time <build_sort_time> · sort share <build_sort_share>%
  Stage (probe): time <t> (<share>%) · parallelism <avg>/<max> · sort time <probe_sort_time> · sort share <probe_sort_share>%
```

* `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` join では、共通の `Left:` 行と `Right:` 行のみが出力されます。

`direct` join では、右側は行としてマテリアライズされず直接ルックアップされるキー・バリューストアであるため、`Left:` 行のみが出力されます。

`CROSS` または `COMMA` join、およびキーの等価条件を含まない任意の `ON` セクションでは、`Buffer:` 行に右テーブルがメモリ内でどのように保持されたかが示され、`Spill:` 行にディスクにスピルされたかどうかが表示されます。

```txt theme={null}
Buffer: memory <peak_memory> · compressed <yes|no>
Spill: yes · right spilled <right_spilled_bytes>
```

* `memory <peak_memory>` — バッファリングされた右テーブルが使用したピークメモリ。
* `compressed <yes|no>` — バッファリングされたブロックが少なくとも1つ圧縮されているかどうか。圧縮されている場合、reader は保存されているすべてのブロックを展開します。
* `Spill:` — `grace_hash` と同じ `yes`/`no` フラグで、`right spilled <right_spilled_bytes>` はディスクに書き込まれた圧縮バイト数を示します。

ここでは両側で `matched not collected` が報告されます。定数の predicate では、すべての左行がすべての右行と組み合わされるか、まったく組み合わされないかのいずれかとなるため、個々のどの行が一致したかを特定することはできません。

[`Join`](/ja/reference/engines/table-engines/special/join) テーブルエンジンとの join では、事前構築済みテーブルを説明する `Hash table:` 行とともに、両側が報告されます。右側では、クエリごとの build の行数ではなく、エンジンに格納されている行数がカウントされます。

<div id="explain-analyze-processors">
  #### プロセッサごとの時間
</div>

`processors = 1` の場合、各ステージの下に追加の行が出力され、そのステージのプロセッサごとの経過時間の分布が表示されます。

```txt theme={null}
Time per processor (<n>): min <t> · median <t> · max <t> · sum <t>
```

`<n>` はそのステージのプロセッサ数です。`median` と `max` の間に大きなギャップがある場合は、並列プロセッサ間で負荷に偏りがあることを示します。

<div id="explain-estimate">
  ### EXPLAIN ESTIMATE
</div>

クエリの実行時に、テーブルから読み取られると推定される行数、マーク数、パーツ数を表示します。[MergeTree](/ja/reference/engines/table-engines/mergetree-family/mergetree) ファミリーのテーブルで使用できます。

**例**

テーブルを作成します。

```sql title="Query" theme={null}
CREATE TABLE ttt (i Int64) ENGINE = MergeTree() ORDER BY i SETTINGS index_granularity = 16, write_final_mark = 0;
INSERT INTO ttt SELECT number FROM numbers(128);
OPTIMIZE TABLE ttt;
```

```sql title="Query" theme={null}
EXPLAIN ESTIMATE SELECT * FROM ttt;
```

```text title="Response" theme={null}
┌─database─┬─table─┬─parts─┬─rows─┬─marks─┐
│ default  │ ttt   │     1 │  128 │     8 │
└──────────┴───────┴───────┴──────┴───────┘
```

<div id="explain-whatif">
  ### EXPLAIN WHATIF
</div>

仮想的なスキップ索引をディスク上に*マテリアライズ*することなく、それが `SELECT` クエリにもたらす効果を見積もります。[`CREATE HYPOTHETICAL INDEX`](/ja/reference/statements/hypothetical-index#create-hypothetical-index) で 1 つ以上の候補を定義し、`EXPLAIN WHATIF SELECT ...` を実行すると、各候補について、適用可否、推定読み取りマーク数、推定バイト数、スキップ率を確認できます。

**構文**

```sql theme={null}
EXPLAIN WHATIF [empirical = 0] SELECT ...
```

**設定**

* `empirical` — `1` (デフォルト) では、スキップ率 (上限値) を測定するため、ベースラインで絞り込まれたグラニュールに対してメモリ内で索引を適用します。`0` ではその処理をスキップします。いずれの場合も、`empirical` で結果が得られない場合 (無効になっている、または索引をメモリ内で評価できない場合) 、推定器はカラム [STATISTICS](/ja/reference/engines/table-engines/mergetree-family/mergetree#column-statistics) にフォールバックし、それも利用できなければ、最終的に適用可否のみのサマリーにフォールバックします。

**出力**

```text theme={null}
Baseline (after PK + partition + existing indexes):
  table:       db.t
  parts:       1
  marks:       100
  est_bytes:   1.50 MiB             (only when the query reads rows)

With idx_b (minmax, hypothetical):
  status:       applicable
  marks:        1
  est_bytes:    15.00 KiB           (only when baseline bytes are known)
  skip_ratio:   99.0%

Estimation:
  source:           empirical | statistical | applicability_only
  empirical_status: ok | unsupported | disabled
  sampled_parts:    50 / 100        (only when source = empirical)
  sampled_marks:    50 / 100        (only when source = empirical)
  elapsed_us:       631             (only when source = empirical)
```

* `source` — 推定値の算出方法を示します。
  * `empirical`: ベースラインで pruned されたグラニュールを対象に、メモリ内で索引を構築し、その索引によってスキップされるグラニュール数を数えます。これは上限値です。制限事項については [`CREATE HYPOTHETICAL INDEX`](/ja/reference/statements/hypothetical-index#limitations) を参照してください。
  * `statistical`: カラム STATISTICS から導出されます。empirical が無効化されている場合 (`empirical = 0`) 、または empirical で結果を生成できず、かつ関連するカラムにカラム STATISTICS が定義されている場合に使用されます。
  * `applicability_only`: 索引は predicate に適用可能ですが、empirical と statistical のいずれでも結果を生成できなかったことを示します (たとえば `empirical = 0` でカラム STATISTICS が定義されていない場合) 。保守的な上限として `skip_ratio: 0.0%` を返します。
* `sampled_parts` / `sampled_marks` — `<baseline-pruned> / <total in the table>`。テーブル全体のうち、PK、partition、既存の索引による pruning を通過した割合、つまり仮想索引への入力となる部分を示します。
* `est_bytes` — 読み取られるバイト数の推定値です。テーブルの平均行サイズから導出されるため概算であり、ストレージや圧縮によって変動します。ベースラインの行はクエリが行を読み取る場合にのみ表示され、候補ごとの行はベースラインのバイト推定値がわかっている場合にのみ表示されます。

この設定は `WHATIF` と `SELECT` の間にインラインで記述します。`SETTINGS` キーワードはありません (これは、他の `EXPLAIN` バリアントでオプションを受け付ける方法と一致しています) 。

テーブルに仮想索引が定義されていない場合、`EXPLAIN WHATIF` は `status: not_applicable` を返し、作成を促すヒントを表示します。

**結合行 (複数候補)**

2 つ以上の候補が empirical で評価されると、`EXPLAIN WHATIF` は候補ごとの行の後に `(combined: idx_a, idx_b, ...)` という名前の追加ブロックを 1 つ付加します。これは、それらすべての索引を同時に持つ場合の総合的な効果を示します。実際の読み取りでは、あるグラニュールが保持されるのは、それが *すべて* のスキップ索引を通過した場合だけなので、結合推定値は各候補で生き残るグラニュールの積集合になります。したがって、この `skip_ratio` は少なくとも最良の単一候補と同等以上になります。相補的な索引は組み合わせることでより多くを prune し、冗長な索引では変化しません。

寄与するのは `source: empirical` の候補だけです。これは、結合された行が各 グラニュール ごとの生存集合の積集合を取って構築されるためです。`statistical` または `applicability_only` と推定された候補には グラニュール ごとのデータがないため除外されます。その結果、結合ブロックが表示されるのは少なくとも 2 つの候補が経験則ベースの推定を生成した場合だけで、それ以外の場合 (たとえば `empirical = 0` の場合) には省略されます。その推定フィールドは、`elapsed_us` が `0` である点を除き、候補ごとの経験則ベースのブロックと同じです — 結合推定は候補ごとのスキャンから導出されるものであり、新たなスキャンではありません。合成された `(combined: ...)` という名前はレポート用ラベルにすぎず、`force_data_skipping_indices` では使用できません。

**経験則ベースの例**

```sql theme={null}
CREATE TABLE t (a UInt64, b UInt64) ENGINE = MergeTree ORDER BY a
SETTINGS index_granularity = 100;

INSERT INTO t SELECT number, number FROM numbers(10000);

CREATE HYPOTHETICAL INDEX idx_b ON t (b) TYPE minmax GRANULARITY 1;

EXPLAIN WHATIF SELECT * FROM t WHERE b = 42;
```

```text theme={null}
Baseline (after PK + partition + existing indexes):
  table:       default.t
  parts:       1
  marks:       100
  est_bytes:   85.52 KiB

With idx_b (minmax, hypothetical):
  status:       applicable
  marks:        1
  est_bytes:    875.00 B
  skip_ratio:   99.0%

Estimation:
  source:           empirical
  empirical_status: ok
  sampled_parts:    1 / 1
  sampled_marks:    100 / 100
```

仮に `minmax` を使うと、100 個のマークを 1 個まで絞り込めます — `skip_ratio: 99.0%`。(`est_bytes` は平均行サイズに基づく推定値のため、正確な値は変動します。)

**統計の例**

[カラム STATISTICS](/ja/reference/engines/table-engines/mergetree-family/mergetree#column-statistics)はデフォルトで無効になっています。`statistical` パスを試すには、まず対象のカラムでこれらを定義し、materialize mutation が完了するまで待ちます:

```sql theme={null}
ALTER TABLE t ADD STATISTICS b TYPE TDigest;
ALTER TABLE t MATERIALIZE STATISTICS b SETTINGS mutations_sync = 1;
```

次に、推定器がカラム STATISTICS を使用するよう、経験則ベースのパスを無効にします：

```sql theme={null}
EXPLAIN WHATIF empirical = 0 SELECT * FROM t WHERE b < 10;
```

```text theme={null}
With idx_b (minmax, hypothetical):
  status:       applicable
  marks:        1
  est_bytes:    1.66 KiB
  skip_ratio:   99.9%

Estimation:
  source:           statistical
  empirical_status: disabled
```

この数値は、`b < 10` のカラム STATISTICS における選択性 (10000 行中およそ 10 行) に基づくもので、`skip_ratio` の上限として報告されます。`sampled_parts` / `sampled_marks` はなく、データは読み取られていません。

どちらの方法も利用できない場合 (たとえば `empirical = 0` で、かつカラム STATISTICS が定義されていない場合) 、推定器は `source: applicability_only` と保守的な `skip_ratio: 0.0%` を報告します。

<div id="explain-table-override">
  ### EXPLAIN TABLE OVERRIDE
</div>

テーブル関数を介してアクセスするテーブルのスキーマに対して、テーブルオーバーライドを適用した結果を表示します。
また、いくつかの検証も行い、オーバーライドによって何らかの問題が発生する場合は例外をスローします。

**例**

次のようなリモート MySQL テーブルがあるとします。

```sql title="Query" theme={null}
CREATE TABLE db.tbl (
    id INT PRIMARY KEY,
    created DATETIME DEFAULT now()
)
```

```sql title="Query" theme={null}
EXPLAIN TABLE OVERRIDE mysql('127.0.0.1:3306', 'db', 'tbl', 'root', 'clickhouse')
PARTITION BY toYYYYMM(assumeNotNull(created))
```

```text title="Response" theme={null}
┌─explain─────────────────────────────────────────────────┐
│ PARTITION BY uses columns: `created` Nullable(DateTime) │
└─────────────────────────────────────────────────────────┘
```

<Note>
  検証は完全ではないため、クエリが成功しても、そのオーバーライドが問題を引き起こさないことは保証されません。
</Note>
