EXPLAIN 输出格式
输出结构
语法结构执行结果是为 statement
选择的计划的文本描述,可以选择使用执行统计信息进行注释。
以下以 TPCH 中数据集的查询分析为例,演示输出结构:
explain SELECT * FROM customer WHERE c_nationkey = (SELECT n_nationkey FROM nation
WHERE customer.c_nationkey = nation.n_nationkey AND nation.n_nationkey > 5);
mysql> explain SELECT * FROM customer WHERE c_nationkey = (SELECT n_nationkey FROM nation
-> WHERE customer.c_nationkey = nation.n_nationkey AND nation.n_nationkey > 5);
+----------------------------------------------------------------------+
| QUERY PLAN |
+----------------------------------------------------------------------+
| Project |
| -> Filter |
| Filter Cond: (customer.c_nationkey = nation.n_nationkey) |
| -> Join |
| Join Type: SINGLE hashOnPK |
| Join Cond: (customer.c_nationkey = nation.n_nationkey) |
| -> Table Scan on tpch.customer |
| -> Table Scan on tpch.nation |
| Filter Cond: (nation.n_nationkey > 5) |
| Block Filter Cond: (nation.n_nationkey > 5) |
+----------------------------------------------------------------------+
10 rows in set (0.01 sec)
EXPLAIN 输出一个名称为 QUERY PLAN
树形结构,每个叶子节点都包含节点类型、受影响的对象。我们现在只使用节点类型信息来简化展示上面的示例。QUERY PLAN
树形结构可以可视化 SQL 查询的整个过程,显示它所经过的操作节点。
Project
└── Filter
└── Join
└── Table Scan
└── Table Scan
节点类型
MatrixOne 支持以下节点类型。
节点名称 | 含义 |
---|---|
Values Scan | 处理值的扫描 |
Table Scan | 从表中扫描数据 |
External Scan | 处理外部的数据扫描 |
Source Scan | 处理 source 表的数据扫描 |
Project | 对数据进行投影运算 |
Sink | 分发同一份数据给一个 / 多个对象 |
Sink Scan | 读取其他对象分发过来的数据 |
Recursive Scan | 循环 CTE 语法中,处理每次循环结束时的数据,判断是否开启下一轮循环 |
CTE Scan | 循环 CTE 语法中,读每次循环开始时的数据 |
Aggregate | 对数据进行聚合 |
Filter | 对数据进行过滤 |
Join | 对数据进行连接运算 |
Sample | SAMPLE 采样函数,对数据进行抽样 |
Sort | 对数据进行排序 |
Partition | 范围窗口中对数据进行排序,并按值切分 |
Union | 对两个或多个查询的结果集组合 |
Union All | 对两个或多个查询的结果集组合,包括重复行 |
Window | 对数据进行范围窗口计算 |
Time Window | 对数据进行时间窗口计算 |
Fill | 处理时间窗口中的 NULL 值 |
Insert | 对数据进行插入 |
Delete | 对数据进行删除 |
Intersect | 对两个或多个查询的都存在的行组合 |
Intersect All | 对两个或多个查询的都存在的行组合,包括重复行 |
Minus | 比较两个查询的结果,返回存在于第一个查询而在第二个查询中不存在的行 |
Table Function | 通过表函数读取数据 |
PreInsert | 整理要写入的数据 |
PreInsert UniqueKey | 整理要写入到唯一键隐藏表的数据 |
PreInsert SecondaryKey | 整理要写入到次级索引隐藏表的数据 |
PreDelete | 整理分区表所需要删除的数据。 |
On Duplicate Key | 对重复的数据进行更新 |
Fuzzy Filter for duplicate key | 对写入/更新的数据进行去重 |
Lock | 对操作的数据上锁 |
示例
VALUES Scan & Project
mysql> explain select abs(-1);
+-------------------------------+
| QUERY PLAN |
+-------------------------------+
| Project |
| -> Values Scan "*VALUES*" |
+-------------------------------+
2 rows in set (0.00 sec)
Table Scan
mysql> explain select * from customer;
+-----------------------------------+
| QUERY PLAN |
+-----------------------------------+
| Project |
| -> Table Scan on tpch.customer |
+-----------------------------------+
2 rows in set (0.01 sec)
External Scan
mysql> create external table extable(n1 int)infile{"filepath"='yourpath/xx.csv'} ;
Query OK, 0 rows affected (0.03 sec)
mysql> explain select * from extable;
+------------------------------------+
| QUERY PLAN |
+------------------------------------+
| Project |
| -> External Scan on db1.extable |
+------------------------------------+
2 rows in set (0.01 sec)
Sink & Lock & Delete & Insert & PreInsert & Sink Scan
mysql> create table t3(n1 int);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into t3 values(1);
Query OK, 1 row affected (0.01 sec)
mysql> explain update t3 set n1=2;
+-----------------------------------------------+
| QUERY PLAN |
+-----------------------------------------------+
| Plan 0: |
| Sink |
| -> Lock |
| -> Project |
| -> Project |
| -> Table Scan on tpch.t3 |
| Plan 1: |
| Delete on tpch.t3 |
| -> Sink Scan |
| DataSource: Plan 0 |
| Plan 2: |
| Insert on tpch.t3 |
| -> Project |
| -> PreInsert on tpch.t3 |
| -> Project |
| -> Sink Scan |
| DataSource: Plan 0 |
+-----------------------------------------------+
17 rows in set (0.00 sec)
Recursive Scan & CTE Scan & Filter
mysql> create table t4(n1 int,n2 int);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into t4 values(1,1),(2,2),(3,3);
Query OK, 3 rows affected (0.01 sec)
mysql> explain WITH RECURSIVE t4_1(n1_1) AS (
-> SELECT n1 FROM t4
-> UNION all
-> SELECT n1_1 FROM t4_1 WHERE n1_1=1
-> )
-> SELECT * FROM t4_1;
+---------------------------------------------------------------------------------------------------+
| QUERY PLAN |
+---------------------------------------------------------------------------------------------------+
| Plan 0: |
| Sink |
| -> Project |
| -> Table Scan on tpch.t4 |
| Plan 1: |
| Sink |
| -> Project |
| -> Filter |
| Filter Cond: (t4_1.n1_1 = 1), mo_check_level((t4_1.__mo_recursive_level_col < 100)) |
| -> Recursive Scan |
| DataSource: Plan 2 |
| Plan 2: |
| Sink |
| -> CTE Scan |
| DataSource: Plan 0, Plan 1 |
| Plan 3: |
| Project |
| -> Sink Scan |
| DataSource: Plan 2 |
+---------------------------------------------------------------------------------------------------+
19 rows in set (0.00 sec)
Aggregate
mysql> explain SELECT count(*) FROM NATION group by N_NAME;
+-------------------------------------------+
| QUERY PLAN |
+-------------------------------------------+
| Project |
| -> Aggregate |
| Group Key: nation.n_name |
| Aggregate Functions: starcount(1) |
| -> Table Scan on tpch.nation |
+-------------------------------------------+
5 rows in set (0.01 sec)
Join
mysql> create table t5(n1 int);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t5 values(1),(2),(3);
Query OK, 3 rows affected (0.01 sec)
mysql> create table t6(n1 int);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t5 values(3),(4),(5);
Query OK, 3 rows affected (0.01 sec)
mysql> explain SELECT * FROM t5 LEFT JOIN t6 ON t5.n1 = t6.n1;
+------------------------------------+
| QUERY PLAN |
+------------------------------------+
| Project |
| -> Join |
| Join Type: LEFT |
| Join Cond: (t5.n1 = t6.n1) |
| -> Table Scan on tpch.t5 |
| -> Table Scan on tpch.t6 |
+------------------------------------+
6 rows in set (0.00 sec)
Sample
mysql> explain SELECT SAMPLE(c_address, 90 percent) FROM customer;
+-----------------------------------------------------+
| QUERY PLAN |
+-----------------------------------------------------+
| Project |
| -> Sample |
| Sample 90.00 Percent by: customer.c_address |
| -> Table Scan on tpch.customer |
+-----------------------------------------------------+
4 rows in set (0.00 sec)
SORT
mysql> explain select * from customer order by c_custkey;
+-----------------------------------------------+
| QUERY PLAN |
+-----------------------------------------------+
| Project |
| -> Sort |
| Sort Key: customer.c_custkey INTERNAL |
| -> Table Scan on tpch.customer |
+-----------------------------------------------+
4 rows in set (0.00 sec)
Partition & Window
mysql>CREATE TABLE t7(n1 int,n2 int);
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t7 values(1,3),(2,2),(3,1);
Query OK, 3 rows affected (0.01 sec)
mysql> explain SELECT SUM(n1) OVER(PARTITION BY n2) AS sn1 FROM t7;
+----------------------------------------------------------+
| QUERY PLAN |
+----------------------------------------------------------+
| Project |
| -> Window |
| Window Function: sum(t7.n1); Partition By: t7.n2 |
| -> Partition |
| Sort Key: t7.n2 INTERNAL |
| -> Table Scan on tpch.t7 |
+----------------------------------------------------------+
6 rows in set (0.01 sec)
Time window & Fill
mysql> CREATE TABLE sensor_data (ts timestamp(3) primary key, temperature FLOAT);
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO sensor_data VALUES('2023-08-01 00:00:00', 25.0);
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO sensor_data VALUES('2023-08-01 00:05:00', 26.0);
Query OK, 1 row affected (0.01 sec)
mysql> explain select _wstart, _wend from sensor_data interval(ts, 10, minute) fill(prev);
+---------------------------------------------------+
| QUERY PLAN |
+---------------------------------------------------+
| Project |
| -> Fill |
| Fill Columns: |
| Fill Mode: Prev |
| -> Time window |
| Sort Key: sensor_data.ts |
| Aggregate Functions: _wstart, _wend |
| -> Table Scan on db2.sensor_data |
+---------------------------------------------------+
8 rows in set (0.00 sec)
Intersect
mysql> explain select * from t5 intersect select * from t6;
+-----------------------------------------+
| QUERY PLAN |
+-----------------------------------------+
| Project |
| -> Intersect |
| -> Project |
| -> Table Scan on tpch.t5 |
| -> Project |
| -> Table Scan on tpch.t6 |
+-----------------------------------------+
6 rows in set (0.00 sec)
Intersect All
mysql> explain select * from t5 intersect all select * from t6;
+-----------------------------------------+
| QUERY PLAN |
+-----------------------------------------+
| Project |
| -> Intersect All |
| -> Project |
| -> Table Scan on tpch.t5 |
| -> Project |
| -> Table Scan on tpch.t6 |
+-----------------------------------------+
6 rows in set (0.00 sec)
Minus
mysql> explain select * from t5 minus select * from t6;
+-----------------------------------------+
| QUERY PLAN |
+-----------------------------------------+
| Project |
| -> Minus |
| -> Project |
| -> Table Scan on tpch.t5 |
| -> Project |
| -> Table Scan on tpch.t6 |
+-----------------------------------------+
6 rows in set (0.00 sec)
Table Function
mysql> explain select * from unnest('{"a":1}') u;
+-------------------------------------+
| QUERY PLAN |
+-------------------------------------+
| Project |
| -> Table Function on unnest |
| -> Values Scan "*VALUES*" |
+-------------------------------------+
3 rows in set (0.10 sec)
PreInsert UniqueKey & Fuzzy Filter for duplicate key
mysql> CREATE TABLE t8(n1 int,n2 int UNIQUE key);
Query OK, 0 rows affected (0.01 sec)
mysql> explain INSERT INTO t8(n2) values(1);
+---------------------------------------------------------------------------------+
| QUERY PLAN |
+---------------------------------------------------------------------------------+
| Plan 0: |
| Sink |
| -> PreInsert on tpch.t8 |
| -> Project |
| -> Project |
| -> Values Scan "*VALUES*" |
| Plan 1: |
| Sink |
| -> Lock |
| -> PreInsert UniqueKey |
| -> Sink Scan |
| DataSource: Plan 0 |
| Plan 2: |
| Insert on tpch.__mo_index_unique_018e2d16-6629-719d-82b5-036222e9658a |
| -> Sink Scan |
| DataSource: Plan 1 |
| Plan 3: |
| Fuzzy Filter for duplicate key |
| -> Table Scan on tpch.__mo_index_unique_018e2d16-6629-719d-82b5-036222e9658a |
| Filter Cond: (__mo_index_idx_col = 1) |
| Block Filter Cond: (__mo_index_idx_col = 1) |
| -> Sink Scan |
| DataSource: Plan 1 |
| Plan 4: |
| Insert on tpch.t8 |
| -> Sink Scan |
| DataSource: Plan 0 |
+---------------------------------------------------------------------------------+
27 rows in set (0.01 sec)
PreInsert SecondaryKey
mysql> CREATE TABLE t9 ( n1 int , n2 int, KEY key2 (n2) USING BTREE);
Query OK, 0 rows affected (0.02 sec)
mysql> explain INSERT INTO t9(n2) values(2);
+--------------------------------------------------------------------------+
| QUERY PLAN |
+--------------------------------------------------------------------------+
| Plan 0: |
| Sink |
| -> PreInsert on tpch.t9 |
| -> Project |
| -> Project |
| -> Values Scan "*VALUES*" |
| Plan 1: |
| Insert on tpch.__mo_index_secondary_018e2d14-6f20-7db0-babb-c1fd505fd3c5 |
| -> Lock |
| -> PreInsert SecondaryKey |
| -> Sink Scan |
| DataSource: Plan 0 |
| Plan 2: |
| Insert on tpch.t9 |
| -> Sink Scan |
| DataSource: Plan 0 |
+--------------------------------------------------------------------------+
16 rows in set (0.00 sec)