メインコンテンツへスキップ
メインコンテンツへスキップ

EXPLAIN 文

文の実行計画を表示します。

構文:

EXPLAIN [AST | SYNTAX | QUERY TREE | PLAN | PIPELINE | ESTIMATE | TABLE OVERRIDE] [setting = value, ...]
    [
      SELECT ... |
      tableFunction(...) [COLUMNS (...)] [ORDER BY ...] [PARTITION BY ...] [PRIMARY KEY] [SAMPLE BY ...] [TTL ...]
    ]
    [FORMAT ...]

例:

EXPLAIN SELECT sum(number) FROM numbers(10) UNION ALL SELECT sum(number) FROM numbers(10) ORDER BY sum(number) ASC FORMAT TSV;
Union
  Expression (Projection)
    Expression (Before ORDER BY and SELECT)
      Aggregating
        Expression (Before GROUP BY)
          SettingQuotaAndLimits (ストレージ読み取り後の制限とクォータ設定)
            ReadFromStorage (SystemNumbers)
  Expression (Projection)
    MergingSorted (ORDER BY用ソート済みストリームのマージ)
      MergeSorting (ORDER BY用ソート済みブロックのマージ)
        PartialSorting (ORDER BY用各ブロックのソート)
          Expression (Before ORDER BY and SELECT)
            Aggregating
              Expression (Before GROUP BY)
                SettingQuotaAndLimits (ストレージ読み取り後の制限とクォータ設定)
                  ReadFromStorage (SystemNumbers)

EXPLAIN の種類

  • AST — 抽象構文木 (Abstract Syntax Tree)。
  • SYNTAX — AST レベルの最適化後のクエリテキスト。
  • QUERY TREE — Query Tree レベルでの最適化後のクエリツリー。
  • PLAN — クエリ実行プラン。
  • PIPELINE — クエリ実行パイプライン。

EXPLAIN AST

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

例:

EXPLAIN AST SELECT 1;
SelectWithUnionQuery (children 1)
 ExpressionList (children 1)
  SelectQuery (children 1)
   ExpressionList (children 1)
    Literal UInt64_1
EXPLAIN AST ALTER TABLE t1 DELETE WHERE date = today();
  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

EXPLAIN SYNTAX

構文解析後のクエリの抽象構文木 (AST) を表示します。

これは、クエリを解析してクエリ AST とクエリツリーを構築し、必要に応じてクエリアナライザーと最適化パスを実行し、その後クエリツリーをクエリ AST に戻すことで行われます。

設定:

  • oneline – クエリを1行で出力します。デフォルト: 0
  • run_query_tree_passes – クエリツリーをダンプする前にクエリツリーのパス処理を実行します。デフォルト: 0
  • query_tree_passesrun_query_tree_passes が有効な場合に、実行するパス処理の回数を指定します。query_tree_passes を指定しない場合は、すべてのパス処理を実行します。

例:

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;

Output:

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 を有効にした場合:

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;

出力:

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

EXPLAIN QUERY TREE

Settings:

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

Example:

EXPLAIN QUERY TREE SELECT id, value FROM test_table;
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

EXPLAIN PLAN

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

設定:

  • header — ステップの出力ヘッダーを表示します。デフォルト: 0。
  • description — ステップの説明を表示します。デフォルト: 1。
  • indexes — 使用された索引と、適用された各索引ごとにフィルタリングされたパーツ数およびグラニュール数を表示します。デフォルト: 0。MergeTree テーブルでサポートされます。ClickHouse >= v25.9 では、このステートメントは SETTINGS use_query_condition_cache = 0, use_skip_indexes_on_data_read = 0 と併用した場合にのみ有用な出力を返します。
  • projections — 解析されたすべてのプロジェクションと、プロジェクションの主キー条件に基づくパーツレベルでのフィルタリングへの影響を表示します。各プロジェクションについて、このセクションには、そのプロジェクションの主キーを使って評価されたパーツ数、行数、マーク数、範囲数といった統計情報が含まれます。また、プロジェクション自体からデータを読み込むことなく、このフィルタリングによりスキップされたデータパーツの数も示します。プロジェクションが実際に読み取りに使用されたか、あるいはフィルタリングのために解析されたのみかは、description フィールドから判別できます。デフォルト: 0。MergeTree テーブルでサポートされます。
  • actions — ステップ内のアクションに関する詳細情報を表示します。デフォルト: 0。
  • json — クエリプランのステップを JSON 形式の行として表示します。デフォルト: 0。不要なエスケープを避けるため、TabSeparatedRaw (TSVRaw) 形式の使用を推奨します。
  • input_headers - ステップの入力ヘッダーを表示します。デフォルト: 0。主に、入力・出力ヘッダーの不整合に関連する問題をデバッグする開発者にとって有用です。
  • column_structure - ヘッダー内のカラム名と型に加えて、そのカラムの構造も表示します。デフォルト: 0。主に、入力・出力ヘッダーの不整合に関連する問題をデバッグする開発者にとって有用です。

json=1 の場合、ステップ名には一意なステップ識別子を含む追加のサフィックスが付きます。

例:

EXPLAIN SELECT sum(number) FROM numbers(10) GROUP BY number % 4;
Union
  Expression (Projection)
  Expression (Before ORDER BY and SELECT)
    Aggregating
      Expression (Before GROUP BY)
        SettingQuotaAndLimits (Set limits and quota after reading from storage)
          ReadFromStorage (SystemNumbers)
注記

ステップおよびクエリのコスト見積もりには対応していません。

json = 1 の場合、クエリプランは JSON 形式で表現されます。各ノードは、必ず Node TypePlans というキーを持つ辞書型オブジェクトです。Node Type はステップ名を表す文字列であり、Plans は子ステップの記述を含む配列です。ノードの種類と設定に応じて、その他の任意のキーが追加される場合があります。

例:

EXPLAIN json = 1, description = 0 SELECT 1 UNION ALL SELECT 2 FORMAT TSVRaw;
[
  {
    "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 キーが追加されます。

{
  "Node Type": "ReadFromStorage",
  "Description": "SystemOne"
}

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

例:

EXPLAIN json = 1, description = 0, header = 1 SELECT 1, 2 + dummy;
[
  {
    "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 キー(文字列 MinMaxPartitionPrimaryKey または Skip)と、以下の任意のキーを持つ場合があります:

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

例:

"Node Type": "ReadFromMergeTree",
"Indexes": [
  {
    "Type": "MinMax",
    "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 キーが追加されます。これは解析された projection の配列を含みます。各 projection は、次のキーを持つ JSON で表現されます。

  • Name — projection 名。
  • Condition — 使用された projection の primary key 条件。
  • Description — projection の使用方法の説明(例: パーツレベルのフィルタリング)。
  • Selected Parts — projection によって選択されたパーツの数。
  • Selected Marks — 選択された mark の数。
  • Selected Ranges — 選択された range の数。
  • Selected Rows — 選択された行の数。
  • Filtered Parts — パーツレベルのフィルタリングによりスキップされたパーツの数。

例:

"Node Type": "ReadFromMergeTree",
"Projections": [
  {
    "Name": "region_proj",
    "Description": "プロジェクションが分析され、パーツレベルのフィルタリングに使用されています",
    "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": "プロジェクションが分析され、パーツレベルのフィルタリングに使用されています",
    "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 の場合、追加されるキーはステップタイプによって異なります。

例:

EXPLAIN json = 1, actions = 1, description = 0 SELECT 1 FORMAT TSVRaw;
[
  {
    "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"
        }
      ]
    }
  }
]

EXPLAIN PIPELINE

設定:

  • header — 各出力ポートごとにヘッダーを出力します。デフォルト: 0。
  • graphDOT グラフ記述言語で表現されたグラフを出力します。デフォルト: 0。
  • compactgraph 設定が有効な場合に、グラフをコンパクトモードで出力します。デフォルト: 1。

compact=0 かつ graph=1 のとき、プロセッサー名には、一意のプロセッサー識別子を含む追加のサフィックスが付きます。

例:

EXPLAIN PIPELINE SELECT sum(number) FROM numbers_mt(100000) GROUP BY number % 4;
(Union)
(Expression)
ExpressionTransform
  (Expression)
  ExpressionTransform
    (Aggregating)
    Resize 2 → 1
      AggregatingTransform × 2
        (Expression)
        ExpressionTransform × 2
          (SettingQuotaAndLimits)
            (ReadFromStorage)
            NumbersRange × 2 0 → 1

EXPLAIN ESTIMATE

クエリを実行する際に、テーブルから読み取られる推定行数、マーク数、およびパーツ数を表示します。MergeTree ファミリーのテーブルで利用できます。

テーブルの作成:

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;

クエリ:

EXPLAIN ESTIMATE SELECT * FROM ttt;

結果:

┌─database─┬─table─┬─parts─┬─rows─┬─marks─┐
│ default  │ ttt   │     1 │  128 │     8 │
└──────────┴───────┴───────┴──────┴───────┘

EXPLAIN TABLE OVERRIDE

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

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

CREATE TABLE db.tbl (
    id INT PRIMARY KEY,
    created DATETIME DEFAULT now()
)
EXPLAIN TABLE OVERRIDE mysql('127.0.0.1:3306', 'db', 'tbl', 'root', 'clickhouse')
PARTITION BY toYYYYMM(assumeNotNull(created))

結果:

┌─explain─────────────────────────────────────────────────┐
│ PARTITION BY uses columns: `created` Nullable(DateTime) │
└─────────────────────────────────────────────────────────┘
注記

検証は完全ではないため、クエリが成功しても、そのオーバーライドによって問題が発生しないことは保証されません。