逻辑计划管理在OceanBase 4.1不足之处
- 复杂计划的可读性不好
以下计划为例,包含多达45个算子,使得用户难以清晰地阅读和理解整个计划。例如,在识别9号JOIN算子的左右子计划时,用户往往需要对照计划表数空格来确认。
=======================================================================================
|ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)|
---------------------------------------------------------------------------------------
|0 |TEMP TABLE TRANSFORMATION | |2 |2473 |
|1 | TEMP TABLE INSERT |TEMP3 |1 |176 |
|2 | MERGE GROUP BY | |1 |176 |
|3 | PX COORDINATOR | |4 |176 |
|4 | EXCHANGE OUT DISTR |:EX10000 |4 |174 |
|5 | MERGE GROUP BY | |4 |172 |
|6 | PX BLOCK ITERATOR | |38 |171 |
|7 | TABLE SCAN |STORE_SALES |38 |171 |
|8 | TOP-N SORT | |2 |2298 |
|9 | NESTED-LOOP JOIN | |2 |2297 |
|10| HASH JOIN | |2 |2235 |
|11| SUBPLAN SCAN |V21 |2 |1087 |
|12| WINDOW FUNCTION | |20 |1086 |
|13| PX COORDINATOR MERGE SORT | |20 |1071 |
|14| EXCHANGE OUT DISTR |:EX20002 |20 |1057 |
|15| SORT | |20 |1042 |
|16| HASH GROUP BY | |20 |1040 |
|17| EXCHANGE IN DISTR | |593 |950 |
|18| EXCHANGE OUT DISTR (HASH) |:EX20001 |593 |750 |
|19| MATERIAL | |593 |301 |
|20| HASH GROUP BY | |593 |301 |
|21| NESTED-LOOP JOIN CARTESIAN | |795 |157 |
|22| EXCHANGE IN DISTR | |1 |2 |
|23| EXCHANGE OUT DISTR (BROADCAST) |:EX20000 |1 |2 |
|24| TEMP TABLE ACCESS |VIEW9(TEMP3)|1 |1 |
|25| PX BLOCK ITERATOR | |795 |145 |
|26| TABLE SCAN |SS1 |795 |145 |
|27| NESTED-LOOP JOIN | |2 |1149 |
|28| SUBPLAN SCAN |V11 |2 |1087 |
|29| WINDOW FUNCTION | |20 |1086 |
|30| PX COORDINATOR MERGE SORT | |20 |1071 |
|31| EXCHANGE OUT DISTR |:EX30002 |20 |1057 |
|32| SORT | |20 |1042 |
|33| HASH GROUP BY | |20 |1040 |
|34| EXCHANGE IN DISTR | |593 |950 |
|35| EXCHANGE OUT DISTR (HASH) |:EX30001 |593 |750 |
|36| MATERIAL | |593 |301 |
|37| HASH GROUP BY | |593 |301 |
|38| NESTED-LOOP JOIN CARTESIAN | |795 |157 |
|39| EXCHANGE IN DISTR | |1 |2 |
|40| EXCHANGE OUT DISTR (BROADCAST)|:EX30000 |1 |2 |
|41| TEMP TABLE ACCESS |VIEW8(TEMP3)|1 |1 |
|42| PX BLOCK ITERATOR | |795 |145 |
|43| TABLE SCAN |SS1 |795 |145 |
|44| DISTRIBUTED TABLE GET |I1 |1 |16 |
|45| DISTRIBUTED TABLE GET |I2 |1 |16 |
=======================================================================================
- plan cache内的计划信息偏少
当前用户只能通过查询GV$PLAN_CACHE_PLAN_EXPLAIN视图获取plan cache内的计划信息。例如下面的计划,无法获取group by的分组列,hash join的连接条件以及基表的过滤条件等等信息。
OceanBase(SYS@SYS)>select * from gv$ob_plan_cache_plan_explain where tenant_id=1002 and svr_ip='100.83.6.130' and svr_port=25611 and plan_id=863;
+-----------+--------------+----------+---------+------------+--------------+-------------------+------+------+------+----------------------------------------------------------------------------------------------------------------------+
| TENANT_ID | SVR_IP | SVR_PORT | PLAN_ID | PLAN_DEPTH | PLAN_LINE_ID | OPERATOR | NAME | ROWS | COST | PROPERTY |
+-----------+--------------+----------+---------+------------+--------------+-------------------+------+------+------+----------------------------------------------------------------------------------------------------------------------+
| 1002 | 100.83.6.130 | 25611 | 863 | 0 | 0 | PHY_HASH_GROUP_BY | NULL | 1 | 4 | NULL |
| 1002 | 100.83.6.130 | 25611 | 863 | 1 | 1 | PHY_HASH_JOIN | NULL | 1 | 3 | NULL |
| 1002 | 100.83.6.130 | 25611 | 863 | 2 | 2 | PHY_TABLE_SCAN | B | 1 | 1 | table_rows:1, physical_range_rows:1, logical_range_rows:1, index_back_rows:0, output_rows:1, avaiable_index_name[T1] |
| 1002 | 100.83.6.130 | 25611 | 863 | 2 | 3 | PHY_TABLE_SCAN | A | 1 | 1 | table_rows:1, physical_range_rows:1, logical_range_rows:1, index_back_rows:0, output_rows:1, avaiable_index_name[T1] |
+-----------+--------------+----------+---------+------------+--------------+-------------------+------+------+------+----------------------------------------------------------------------------------------------------------------------+
- 无法查看演进计划信息
OceanBase 4.1版本推出了计划演进功能,旨在预防计划出现性能倒退的情况。对于特定的查询,可能存在多个计划在进行演进。目前,用户仅能通过DBA_SQL_PLAN_BASELINES视图查询计划的演进状态,但无法直接获取到关于演进中计划的具体信息。
OceanBase(SYS@SYS)>select * from DBA_SQL_PLAN_BASELINES\G
*************************** 1. row ***************************
SIGNATURE: 11986391583431335905
SQL_HANDLE: 529F6E6454EF579C7CC265D1F6131D70
SQL_TEXT: select * from t1 where c1 = 1
PLAN_NAME: 11986391583431335905
CREATOR: SYS
ORIGIN: AUTO-CAPTURE
PARSING_SCHEMA_NAME: NULL
DESCRIPTION: NULL
VERSION: 4.1.0.0
CREATED: 2023-03-27 20:54:15.056670
LAST_MODIFIED: 2023-03-27 20:54:15.056670
LAST_EXECUTED: 1679921655053442
LAST_VERIFIED: 1679921655053442
ENABLED: YES
ACCEPTED: YES
FIXED: NO
REPRODUCED: YES
AUTOPURGE: YES
ADAPTIVE: NO
OPTIMIZER_COST: -1
MODULE: NULL
ACTION: NULL
EXECUTIONS: 1
ELAPSED_TIME: 6996
CPU_TIME: 239
BUFFER_GETS: NULL
DISK_READS: NULL
DIRECT_WRITES: NULL
ROWS_PROCESSED: NULL
FETCHES: NULL
END_OF_FETCH_COUNT: NULL
- 无法查看session正在执行的计划信息。
这是一个很常见的场景,当用户在调优AP查询时,会尝试执行一次查询,如果查询执行时间较长,我们无法获取查询的执行情况,只有等查询结束才能查看计划的执行信息。
OceanBase v4.2逻辑计划管理特性介绍
逻辑计划管理,旨在提升查询计划的易用性,降低用户阅读、使用查询计划的门槛。主要有以下几个特性。
特性1:为计划绘制树状信息
有了树状结构信息之后,用户能够更加方便的阅读计划。
========================================================================================================
|ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)|
--------------------------------------------------------------------------------------------------------
|0 |TEMP TABLE TRANSFORMATION | |2 |2473 |
|1 |├─TEMP TABLE INSERT |TEMP3 |1 |176 |
|2 |│ └─MERGE GROUP BY | |1 |176 |
|3 |│ └─PX COORDINATOR | |4 |176 |
|4 |│ └─EXCHANGE OUT DISTR |:EX10000 |4 |174 |
|5 |│ └─MERGE GROUP BY | |4 |172 |
|6 |│ └─PX BLOCK ITERATOR | |38 |171 |
|7 |│ └─TABLE FULL SCAN |STORE_SALES |38 |171 |
|8 |└─TOP-N SORT | |2 |2298 |
|9 | └─NESTED-LOOP JOIN | |2 |2297 |
|10| ├─HASH JOIN | |2 |2235 |
|11| │ ├─SUBPLAN SCAN |V21 |2 |1087 |
|12| │ │ └─WINDOW FUNCTION | |20 |1086 |
|13| │ │ └─PX COORDINATOR MERGE SORT | |20 |1071 |
|14| │ │ └─EXCHANGE OUT DISTR |:EX20002 |20 |1057 |
|15| │ │ └─SORT | |20 |1042 |
|16| │ │ └─HASH GROUP BY | |20 |1040 |
|17| │ │ └─EXCHANGE IN DISTR | |593 |950 |
|18| │ │ └─EXCHANGE OUT DISTR (HASH) |:EX20001 |593 |750 |
|19| │ │ └─MATERIAL | |593 |301 |
|20| │ │ └─HASH GROUP BY | |593 |301 |
|21| │ │ └─NESTED-LOOP JOIN CARTESIAN | |795 |157 |
|22| │ │ ├─EXCHANGE IN DISTR | |1 |2 |
|23| │ │ │ └─EXCHANGE OUT DISTR (BROADCAST) |:EX20000 |1 |2 |
|24| │ │ │ └─TEMP TABLE ACCESS |VIEW9(TEMP3)|1 |1 |
|25| │ │ └─PX BLOCK ITERATOR | |795 |145 |
|26| │ │ └─TABLE FULL SCAN |SS1 |795 |145 |
|27| │ └─NESTED-LOOP JOIN | |2 |1149 |
|28| │ ├─SUBPLAN SCAN |V11 |2 |1087 |
|29| │ │ └─WINDOW FUNCTION | |20 |1086 |
|30| │ │ └─PX COORDINATOR MERGE SORT | |20 |1071 |
|31| │ │ └─EXCHANGE OUT DISTR |:EX30002 |20 |1057 |
|32| │ │ └─SORT | |20 |1042 |
|33| │ │ └─HASH GROUP BY | |20 |1040 |
|34| │ │ └─EXCHANGE IN DISTR | |593 |950 |
|35| │ │ └─EXCHANGE OUT DISTR (HASH) |:EX30001 |593 |750 |
|36| │ │ └─MATERIAL | |593 |301 |
|37| │ │ └─HASH GROUP BY | |593 |301 |
|38| │ │ └─NESTED-LOOP JOIN CARTESIAN | |795 |157 |
|39| │ │ ├─EXCHANGE IN DISTR | |1 |2 |
|40| │ │ │ └─EXCHANGE OUT DISTR (BROADCAST)|:EX30000 |1 |2 |
|41| │ │ │ └─TEMP TABLE ACCESS |VIEW8(TEMP3)|1 |1 |
|42| │ │ └─PX BLOCK ITERATOR | |795 |145 |
|43| │ │ └─TABLE FULL SCAN |SS1 |795 |145 |
|44| │ └─DISTRIBUTED TABLE GET |I1 |1 |16 |
|45| └─DISTRIBUTED TABLE GET |I2 |1 |16 |
========================================================================================================
特性2:更加明确的参数化信息
4.2版本之前参数的表达式信息都是展示成"?",无法从计划中区分不同的参数,也不知道参数的真实值。现在查询计划会给参数编号,例如:0
,同时也会给出参数对应的值,例如:0 => 2
,并且还会展示计划的约束信息,例如:1 IS NOT NULL result is TRUE
,即只有当第一个参数不为NULL时,才能命中该计划。
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T_FUN_COUNT(*)]), filter(nil), rowset=256 |
| group([A.C2]), agg_func([T_FUN_COUNT(*)]) |
| 1 - output([A.C2]), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 2 - output([A.C2]), filter([A.C1 = :0]), rowset=256 |
| access([A.C1], [A.C2]), partitions(p0) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([A.__pk_increment]), range(MIN ; MAX)always true |
| 3 - output(nil), filter(nil), rowset=256 |
| 4 - output(nil), filter([:0 = B.C1]), rowset=256 |
| access([B.C1]), partitions(p0) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([B.__pk_increment]), range(MIN ; MAX)always true | | |
| Plan Type: |
| LOCAL |
| Parameters: |
| :0 => 2 |
| :1 => 2 |
| Expr Constraints: |
| :1 IS NOT NULL result is TRUE |
特性3:第一次生成计划的真实信息
plan cache除了会保存查询的逻辑计划信息外,还会保存计划的第一次执行反馈信息(真实的执行情况)
==============================================================================================================
|ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)|REAL.ROWS|REAL.TIME(us)|IO TIME(us)|CPU TIME(us)|
--------------------------------------------------------------------------------------------------------------
|0 |HASH GROUP BY | |13 |10753 |1 |37990 |0 |0 |
|1 |└─NESTED-LOOP JOIN CARTESIAN | |163 |10735 |169 |37990 |0 |0 |
|2 | ├─TABLE FULL SCAN |A |13 |5365 |13 |37990 |0 |0 |
|3 | └─MATERIAL | |13 |5366 |169 |36932 |0 |0 |
|4 | └─TABLE FULL SCAN |B |13 |5365 |13 |23120 |0 |0 |
==============================================================================================================
计划中EST.ROWS字段表示优化器估算的算子输出行数信息,EST.TIME字段表示优化器估算的执行时间(计划从开始到该算子结束计算的耗时),单位为微秒,REAL.ROWS字段表示算子的真实输出行数信息,REAL.TIME字段表示算子的真实执行时间,IO TIME字段表示该算子的IO/网络开销,CPU TIME字段表示该算子的CPU开销。
通过执行反馈信息,用户可以初步确定计划的估行问题、代价估算问题,以及计划执行的热点算子,明确用户排查问题的方向。
特性4:session实时计划信息
用户正在执行一条很大的查询,例如:
OceanBase(SYS@SYS)>insert /*+parallel(2) enable_parallel_dml*/ into t1 select level,level from t2 connect by level < 200000;
通过show processlist可以看到当前查询正在执行。
OceanBase(SYS@SYS)>show processlist;
+------------+------+--------------------+------+---------+------+--------+----------------------------------------------------------------------------------------------------------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+------------+------+--------------------+------+---------+------+--------+----------------------------------------------------------------------------------------------------------+
| 3221552571 | SYS | 11.158.31.44:38100 | SYS | Query | 1 | ACTIVE | insert /*+parallel(2) enable_parallel_dml*/ into t1 select level,level from t2 connect by level < 200000 |
| 3221553266 | SYS | 11.158.31.44:38715 | SYS | Query | 0 | ACTIVE | show processlist |
+------------+------+--------------------+------+---------+------+--------+----------------------------------------------------------------------------------------------------------+
拿到session ID之后可以进一步获取计划的执行详情。
OceanBase(SYS@SYS)>select * from table(dbms_xplan.display_active_session_plan(3221552571));
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| COLUMN_VALUE |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ======================================================================================================================================= |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)|REAL.ROWS|REAL.TIME(us)|IO TIME(us)|CPU TIME(us)| |
| --------------------------------------------------------------------------------------------------------------------------------------- |
| |0 |PX COORDINATOR | |2 |72 |0 |0 |1614 |0 | |
| |1 |└─EXCHANGE OUT DISTR |:EX10003 |2 |71 |0 |0 |0 |0 | |
| |2 | └─INSERT | |2 |70 |0 |0 |0 |0 | |
| |3 | └─EXCHANGE IN DISTR | |2 |54 |123392 |0 |419 |0 | |
| |4 | └─EXCHANGE OUT DISTR (RANDOM) |:EX10002 |2 |54 |150784 |0 |761 |463 | |
| |5 | └─MATERIAL | |2 |52 |150784 |0 |0 |0 | |
| |6 | └─OPTIMIZER STATS GATHER | |2 |52 |199999 |822113 |0 |0 | |
| |7 | └─SUBPLAN SCAN |ANONYMOUS_VIEW1|2 |52 |199999 |794630 |0 |0 | |
| |8 | └─NESTED-LOOP CONNECT BY | |2 |52 |199999 |794630 |0 |0 | |
| |9 | ├─MATERIAL | |1 |2 |1 |796762 |0 |0 | |
| |10| │ └─EXCHANGE IN DISTR | |1 |2 |1 |0 |2 |0 | |
| |11| │ └─EXCHANGE OUT DISTR |:EX10000 |1 |2 |1 |1059 |0 |0 | |
| |12| │ └─SUBPLAN SCAN |VIEW1 |1 |1 |1 |1059 |0 |0 | |
| |13| │ └─PX BLOCK ITERATOR| |1 |1 |1 |1059 |0 |0 | |
| |14| │ └─TABLE FULL SCAN|T2 |1 |1 |1 |1059 |0 |0 | |
| |15| └─EXCHANGE IN DISTR | |1 |2 |1 |0 |0 |0 | |
| |16| └─EXCHANGE OUT DISTR |:EX10001 |1 |2 |1 |1079 |0 |0 | |
| |17| └─SUBPLAN SCAN |VIEW2 |1 |1 |1 |1079 |0 |0 | |
| |18| └─PX BLOCK ITERATOR | |1 |1 |1 |1079 |0 |0 | |
| |19| └─TABLE FULL SCAN |T2 |1 |1 |1 |1079 |0 |0 | |
| ======================================================================================================================================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output(nil), filter(nil), rowset=256 |
| 1 - output(nil), filter(nil), rowset=256 |
| dop=2 |
| 2 - output(nil), filter(nil) |
| columns([{T1: ({T1: (T1.__pk_increment, T1.C1, T1.C2)})}]), partitions(p0), |
| column_values([T_HIDDEN_PK], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)]) |
| 3 - output([T_HIDDEN_PK], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)]), filter(nil), rowset=256 |
| 4 - output([T_HIDDEN_PK], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)]), filter(nil), rowset=256 |
| is_single, dop=1 |
| 5 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)]), filter(nil), rowset=256 |
| 6 - output([column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)], [column_conv(NUMBER,PS:(-1,0),NULL,ANONYMOUS_VIEW1.LEVEL)]), filter(nil), rowset=256 |
| 7 - output([ANONYMOUS_VIEW1.LEVEL], [ANONYMOUS_VIEW1.LEVEL]), filter(nil), rowset=256 |
| access([ANONYMOUS_VIEW1.LEVEL], [ANONYMOUS_VIEW1.LEVEL]) |
| 8 - output([LEVEL], [LEVEL]), filter(nil) |
| conds([LEVEL < :0]), nl_params_(nil), use_batch=false |
| 9 - output([VIEW1.T2.__pk_increment]), filter(nil), rowset=256 |
| 10 - output([VIEW1.T2.__pk_increment]), filter(nil), rowset=256 |
| 11 - output([VIEW1.T2.__pk_increment]), filter(nil), rowset=256 |
| dop=2 |
通过display_active_session_plan可以查看计划的实时执行情况。
OceanBase v4.2逻辑计划使用说明
explain计划
功能介绍
用户可以通过explain语法可取某条查询的计划信息,OceanBase会保存所有已经explain过的查询。在当前session未断开之前,用户可以通过使用DBMS_XPLAN.display函数查询历史计划信息,断开当前session之后,所有的explain计划将会被清理,无法再次查询。
同时用户可以通过explain into语法指定保存的目标表。
explain into
语句语法如下:
explain [into table_name] explainable_stmt
-
into table_name表示explain的计划信息保存到指定表table_name内
-
如果没有指定into table_name,默认查询到PLAN_TABLE表内
explain into test select count(*) from t1;
select * from table(dbms_xplan.display(table_name=>'test'));
explain set statement_id
语句语法如下:
explain [set statement_id = string] explainable_stmt
-
set statement_id = string表示当前查询使用string标记,以方便后续查询改SQL的计划信息
-
如果没有指定set statement_id,默认使用空串信息标记
explain set statement_id='test2' select count(*) from t1;
select * from table(dbms_xplan.display(statement_id=>'test2'));
相关包函数说明
-- display plan table`s plan
function display(format varchar2 default 'TYPICAL', --'BASIC', 'TYPICAL', 'ALL', 'ADVANCED'
statement_id varchar2 default null,
table_name varchar2 default 'PLAN_TABLE',
filter_preds varchar2 default null)
return dbms_xplan_type_table;
DBMS_XPLAN.DISPLAY用于查询并格式化历史的explain计划,相关参数说明:
- table_name:explain计划保存的目标表,默认是PLAN_TABLE;
- statement_id:explain查询的标记信息,可以通过explain set statement_id='xxx'设置查询的的标记信息;
- format:用于计划格式信息,可选参数有
- 'BASIC':展示少量信息,如算子ID、算子名称、算子备注信息、表达式信息;
- 'TYPICAL':展示基础信息,如算子ID、算子名称、算子备注信息、优化器估计的输出行数、优化器估计的执行时间,表达式信息;如果该计划执行过,还会展示计划第一次执行真实反馈信息,例如真实行数,开销等等。
- 'ALL':展示丰富的计划信息,如算子ID、算子名称、算子备注信息、优化器估计的输出行数、优化器估计的执行时间,表达式信息、生效的hint、query block name trace信息、
- outline信息、基表优化信息、常量参数化信息、约束信息、plan note等等;
- 'ADVANCED':展示丰富的计划信息,计划信息与'ALL'参数一致,除此之外还为复杂的计划展示树状结构信息。
- filter_preds:额外的PLAN_TABLE过滤条件,用于过滤特定的算子或计划。
相关数据字典说明
该函数包依赖的默认表,如果不存在,用户可以自己创建,定义为:
create table PLAN_TABLE (
statement_id varchar2(30),
plan_id int,
gmt_create timestamp,
remarks varchar2(4000),
operator varchar2(255),
options varchar2(255),
object_node varchar2(40),
object_owner varchar2(128),
object_name varchar2(128),
object_alias varchar2(261),
object_instance int,
object_type varchar2(30),
optimizer varchar2(4000),
search_columns int,
id int,
parent_id int,
depth int,
position int,
is_last_child int,
cost int,
cardinality int,
bytes int,
rowset int,
other_tag varchar2(4000),
partition_start varchar2(4000),
partition_stop varchar2(4000),
partition_id int,
other varchar2(4000),
distribution varchar2(64),
cpu_cost int,
io_cost int,
temp_space int,
access_predicates varchar2(4000),
filter_predicates varchar2(4000),
startup_predicates varchar2(4000),
projection varchar2(4000),
special_predicates varchar2(4000),
time int,
qblock_name varchar2(128),
other_xml varchar2(4000)
);
create table plan_table (
statement_id varchar(30),
plan_id int,
gmt_create timestamp,
remarks varchar(4000),
operator varchar(255),
options varchar(255),
object_node varchar(40),
object_owner varchar(128),
object_name varchar(128),
object_alias varchar(261),
object_instance int,
object_type varchar(30),
optimizer varchar(4000),
search_columns int,
id int,
parent_id int,
depth int,
position int,
is_last_child int,
cost int,
cardinality int,
bytes int,
rowset int,
other_tag varchar(4000),
partition_start varchar(4000),
partition_stop varchar(4000),
partition_id int,
other varchar(4000),
distribution varchar(64),
cpu_cost int,
io_cost int,
temp_space int,
access_predicates varchar(4000),
filter_predicates varchar(4000),
startup_predicates varchar(4000),
projection varchar(4000),
special_predicates varchar(4000),
time int,
qblock_name varchar(128),
other_xml varchar(4000)
);
使用示例(oracle租户)
step1: 连接数据库,创建表
create table t1(c1 int);
create table PLAN_TABLE (
statement_id varchar2(30),
plan_id int,
gmt_create timestamp,
remarks varchar2(4000),
operator varchar2(255),
options varchar2(255),
object_node varchar2(40),
object_owner varchar2(128),
object_name varchar2(128),
object_alias varchar2(261),
object_instance int,
object_type varchar2(30),
optimizer varchar2(4000),
search_columns int,
id int,
parent_id int,
depth int,
position int,
is_last_child int,
cost int,
cardinality int,
bytes int,
rowset int,
other_tag varchar2(4000),
partition_start varchar2(4000),
partition_stop varchar2(4000),
partition_id int,
other varchar2(4000),
distribution varchar2(64),
cpu_cost int,
io_cost int,
temp_space int,
access_predicates varchar2(4000),
filter_predicates varchar2(4000),
startup_predicates varchar2(4000),
projection varchar2(4000),
special_predicates varchar2(4000),
time int,
qblock_name varchar2(128),
other_xml varchar2(4000)
);
step2: explain查看计划
explain select * from t1;
step3: 使用DBMS_XPLAN包查看历史计划,oracle租户需要配合function table功能使用
select * from table(dbms_xplan.display);
+-------------------------------------------------------------------+
| COLUMN_VALUE |
+-------------------------------------------------------------------+
| ========================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| ------------------------------------------ |
| |0 |TABLE SCAN|T1 |1 |2 | |
| ========================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T1.C1]), filter(nil), rowset=16 |
| access([T1.C1]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([T1.__pk_increment]), range(MIN ; MAX)always true |
+-------------------------------------------------------------------+
使用示例(mysql租户)
step1: 连接数据库,创建表
create table t1(c1 int);
create table plan_table (
statement_id varchar(30),
plan_id int,
gmt_create timestamp,
remarks varchar(4000),
operator varchar(255),
options varchar(255),
object_node varchar(40),
object_owner varchar(128),
object_name varchar(128),
object_alias varchar(261),
object_instance int,
object_type varchar(30),
optimizer varchar(4000),
search_columns int,
id int,
parent_id int,
depth int,
position int,
is_last_child int,
cost int,
cardinality int,
bytes int,
rowset int,
other_tag varchar(4000),
partition_start varchar(4000),
partition_stop varchar(4000),
partition_id int,
other varchar(4000),
distribution varchar(64),
cpu_cost int,
io_cost int,
temp_space int,
access_predicates varchar(4000),
filter_predicates varchar(4000),
startup_predicates varchar(4000),
projection varchar(4000),
special_predicates varchar(4000),
time int,
qblock_name varchar(128),
other_xml varchar(4000)
);
step2: explain查看计划
explain select * from t1;
step3: 使用DBMS_XPLAN包查看历史计划,mysql租户由于没有function table功能,可以直接在select里面输出计划信息
select dbms_xplan.display() from dual;
+-------------------------------------------------------------------+
| COLUMN_VALUE |
+-------------------------------------------------------------------+
| ========================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| ------------------------------------------ |
| |0 |TABLE SCAN|T1 |1 |2 | |
| ========================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T1.C1]), filter(nil), rowset=16 |
| access([T1.C1]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([T1.__pk_increment]), range(MIN ; MAX)always true |
+-------------------------------------------------------------------+
执行计划
功能介绍
OceanBase会保存用户执行过的所有查询的计划,包括物理计划以及逻辑计划,用户后续排查问题
使用。为了方便用户解读历史查询计划,OceanBase提供了相关了DBMS包格式化计划。不同于explain的计划,用户执行过的计划会一直保存在数据库中,即使用户断开连接。只有当用户重启集群时,数据库才会清理保存的查询计划。
相关包函数说明
-- display sql plan table`s plan
function display_cursor(plan_id integer default 0, -- default value: last plan
format varchar2 default 'TYPICAL',
svr_ip varchar2 default null, -- default value: server connected by client
svr_port integer default 0, -- default value: server connected by client
tenant_id integer default 0 -- default value: current tenant
)
return dbms_xplan_type_table;
参数说明:
plan_id:计划ID,如果不指定,表示上一次执行的计划;
format:计划的格式,同上;
svr_ip、svr_port:计划所在的节点IP,默认是session连接的节点IP;
tenant_id:计划所属租户ID,默认是session当前连接的租户。
相关数据字典说明
计划信息存放所在的数据字典为__all_virtual_sql_plan,每个租户下也有对应的系统视图gvob_sql_plan(当前租户所有机器的计划)、vob_sql_plan(当前租户在当前机器的计划)。
+--------------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+---------------------+------+-----+---------+-------+
| tenant_id | bigint(20) | NO | PRI | NULL | |
| plan_id | bigint(20) | NO | PRI | NULL | |
| svr_ip | varchar(46) | NO | PRI | NULL | |
| svr_port | bigint(20) | NO | PRI | NULL | |
| sql_id | varchar(32) | NO | | NULL | |
| db_id | bigint(20) | NO | | NULL | |
| plan_hash | bigint(20) unsigned | NO | | NULL | |
| gmt_create | timestamp(6) | NO | | NULL | |
| operator | varchar(255) | NO | | NULL | |
| options | varchar(255) | NO | | NULL | |
| object_node | varchar(40) | NO | | NULL | |
| object_id | bigint(20) | NO | | NULL | |
| object_owner | varchar(128) | NO | | NULL | |
| object_name | varchar(128) | NO | | NULL | |
| object_alias | varchar(261) | NO | | NULL | |
| object_type | varchar(20) | NO | | NULL | |
| optimizer | varchar(4000) | NO | | NULL | |
| id | bigint(20) | NO | | NULL | |
| parent_id | bigint(20) | NO | | NULL | |
| depth | bigint(20) | NO | | NULL | |
| position | bigint(20) | NO | | NULL | |
| search_columns | bigint(20) | NO | | NULL | |
| is_last_child | bigint(20) | NO | | NULL | |
| cost | bigint(20) | NO | | NULL | |
| real_cost | bigint(20) | NO | | NULL | |
| cardinality | bigint(20) | NO | | NULL | |
| real_cardinality | bigint(20) | NO | | NULL | |
| bytes | bigint(20) | NO | | NULL | |
| rowset | bigint(20) | NO | | NULL | |
| other_tag | varchar(4000) | NO | | NULL | |
| partition_start | varchar(4000) | NO | | NULL | |
| partition_stop | varchar(4000) | NO | | NULL | |
| partition_id | bigint(20) | NO | | NULL | |
| other | varchar(4000) | NO | | NULL | |
| distribution | varchar(64) | NO | | NULL | |
| cpu_cost | bigint(20) | NO | | NULL | |
| io_cost | bigint(20) | NO | | NULL | |
| temp_space | bigint(20) | NO | | NULL | |
| access_predicates | varchar(4000) | NO | | NULL | |
| filter_predicates | varchar(4000) | NO | | NULL | |
| startup_predicates | varchar(4000) | NO | | NULL | |
| projection | varchar(4000) | NO | | NULL | |
| special_predicates | varchar(4000) | NO | | NULL | |
| time | bigint(20) | NO | | NULL | |
| qblock_name | varchar(128) | NO | | NULL | |
| remarks | varchar(4000) | NO | | NULL | |
| other_xml | varchar(4000) | NO | | NULL | |
+--------------------+---------------------+------+-----+---------+-------+
使用示例(oracle租户)
step1: 连接数据库,创建表
create table t1(c1 int);
step2: 执行查询
select * from t1;
step3: 使用DBMS_XPLAN包查看计划
oracle租户需要配合function table功能使用
select * from table(dbms_xplan.display_cursor());
+--------------------------------------------------------------------------------------------------+
| COLUMN_VALUE |
+--------------------------------------------------------------------------------------------------+
| ================================================================================================ |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)|REAL.ROWS|REAL.TIME(us)|IO TIME(us)|CPU TIME(us)| |
| ------------------------------------------------------------------------------------------------ |
| |0 |TABLE FULL SCAN|T1 |1 |2 |0 |0 |0 |0 | |
| ================================================================================================ |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T1.C1]), filter(nil), rowset=256 |
| access([T1.C1]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([T1.__pk_increment]), range(MIN ; MAX)always true |
+--------------------------------------------------------------------------------------------------+
或者指定(tenant_id, svr_ip, svr_port, plan_id)四元组查询指定计划信息
OceanBase(SYS@SYS)>select * from table(dbms_xplan.display_cursor(
123,
'typical',
'127.0.0.1',
2828,
1002
));
使用示例(mysql租户)
step1: 连接数据库,创建表
create table t1(c1 int);
step2: 执行查询
select * from t1;
step3: 使用DBMS_XPLAN包配合sql_audit查看计划
select dbms_xplan.display_cursor();
+--------------------------------------------------------------------------------------------------+
| COLUMN_VALUE |
+--------------------------------------------------------------------------------------------------+
| ================================================================================================ |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)|REAL.ROWS|REAL.TIME(us)|IO TIME(us)|CPU TIME(us)| |
| ------------------------------------------------------------------------------------------------ |
| |0 |TABLE FULL SCAN|T1 |1 |2 |0 |0 |0 |0 | |
| ================================================================================================ |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T1.C1]), filter(nil), rowset=256 |
| access([T1.C1]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([T1.__pk_increment]), range(MIN ; MAX)always true |
+--------------------------------------------------------------------------------------------------+
或者指定(tenant_id, svr_ip, svr_port, plan_id)四元组查询指定计划信息
OceanBase(SYS@SYS)>select dbms_xplan.display_cursor(
123,
'typical',
'127.0.0.1',
2828,
1002
) from dual;
SPM baseline计划
功能介绍
用户可以通过DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE查看SPM(功能介绍相见SPM)的基线计划,需要指定sql_handle和plan_name。
相关包函数说明
-- display base line plan
function display_sql_plan_baseline(sql_handle varchar2 default NULL,
plan_name varchar2 default NULL,
format varchar2 default 'TYPICAL',
svr_ip varchar2 default null, -- default value: server connected by client
svr_port integer default 0, -- default value: server connected by client
tenant_id integer default 0 -- default value: current tenant
)
return dbms_xplan_type_table;
参数说明:
- sql_handle:baseline计划的handle;
- plan_name:baseline计划的name;
- format:计划的格式,同上;
- svr_ip、svr_port:计划所在的节点IP,默认是session连接的节点IP;
- tenant_id:计划所属租户ID,默认是session当前连接的租户。
使用示例(oracle租户)
开启session的SPM
set session optimizer_use_sql_plan_baselines = 'ON';
set session optimizer_capture_sql_plan_baselines = 'ON';
创建基线计划
create table t1(c1 int);
select * from t1 where c1 > 1;
查询基线计划ID
select sql_handle,plan_name from DBA_SQL_PLAN_BASELINES;
+----------------------------------+----------------------+
| SQL_HANDLE | PLAN_NAME |
+----------------------------------+----------------------+
| 49D6048C041AA8C7E70E2D114250AB99 | 11986391583431335905 |
+----------------------------------+----------------------+
查看基线计划
select * from table(dbms_xplan.display_sql_plan_baseline('49D6048C041AA8C7E70E2D114250AB99','11986391583431335905','all'));
+------------------------------------------------------------------------------------------------------------------+
| COLUMN_VALUE |
+------------------------------------------------------------------------------------------------------------------+
| ================================================================================================ |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)|REAL.ROWS|REAL.TIME(us)|IO TIME(us)|CPU TIME(us)| |
| ------------------------------------------------------------------------------------------------ |
| |0 |TABLE FULL SCAN|T1 |1 |2 |0 |0 |0 |0 | |
| ================================================================================================ |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T1.C1]), filter([T1.C1 > :0]), rowset=256 |
| access([T1.C1]), partitions(p0) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([T1.__pk_increment]), range(MIN ; MAX)always true |
| Used Hint: |
| ------------------------------------- |
| /*+ |
| |
| */ |
| Qb name trace: |
| ------------------------------------- |
| stmt_id:0, SEL$1 |
| Outline Data: |
| ------------------------------------- |
| /*+ |
| BEGIN_OUTLINE_DATA |
| FULL(@"SEL$1" "SYS"."T1"@"SEL$1") |
| OPTIMIZER_FEATURES_ENABLE('4.0.0.0') |
| END_OUTLINE_DATA |
| */ |
| Optimization Info: |
| ------------------------------------- |
| T1: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:0 |
| avaiable_index_name:[T1] |
| stats version:0 |
| Plan Type: |
| LOCAL |
| Parameters: |
| :0 => 1 |
| SQL text: |
| ------------------------------------- |
| select * from t1 where c1 > 1 |
| Outline data: |
| ------------------------------------- |
| /*+BEGIN_OUTLINE_DATA FULL(@"SEL$1" "SYS"."T1"@"SEL$1") OPTIMIZER_FEATURES_ENABLE('4.0.0.0')END_OUTLINE_DATA*/ |
| SQL handle: |
| ------------------------------------- |
| 49D6048C041AA8C7E70E2D114250AB99 |
| Plan name: |
| ------------------------------------- |
| 11986391583431335905 |
| Baseline info: |
| ------------------------------------- |
| Origin: AUTO-CAPTURE Accepted: YES Fixed: NO Enabled: YES |
| Plan rows: From plan cahe |
+------------------------------------------------------------------------------------------------------------------+
使用示例(mysql租户)
开启session的SPM
set session optimizer_use_sql_plan_baselines = 'ON';
set session optimizer_capture_sql_plan_baselines = 'ON';
创建基线计划
create table t1(c1 int);
select * from t1 where c1 > 1;
查询基线计划ID
select sql_handle,plan_name from oceanbase.DBA_SQL_PLAN_BASELINES;
+----------------------------------+----------------------+
| SQL_HANDLE | PLAN_NAME |
+----------------------------------+----------------------+
| 49D6048C041AA8C7E70E2D114250AB99 | 11986391583431335905 |
+----------------------------------+----------------------+
查看基线计划
select dbms_xplan.display_sql_plan_baseline('49D6048C041AA8C7E70E2D114250AB99','11986391583431335905','all');
+------------------------------------------------------------------------------------------------------------------+
| COLUMN_VALUE |
+------------------------------------------------------------------------------------------------------------------+
| ================================================================================================ |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)|REAL.ROWS|REAL.TIME(us)|IO TIME(us)|CPU TIME(us)| |
| ------------------------------------------------------------------------------------------------ |
| |0 |TABLE FULL SCAN|T1 |1 |2 |0 |0 |0 |0 | |
| ================================================================================================ |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T1.C1]), filter([T1.C1 > :0]), rowset=256 |
| access([T1.C1]), partitions(p0) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([T1.__pk_increment]), range(MIN ; MAX)always true |
| Used Hint: |
| ------------------------------------- |
| /*+ |
| |
| */ |
| Qb name trace: |
| ------------------------------------- |
| stmt_id:0, SEL$1 |
| Outline Data: |
| ------------------------------------- |
| /*+ |
| BEGIN_OUTLINE_DATA |
| FULL(@"SEL$1" "SYS"."T1"@"SEL$1") |
| OPTIMIZER_FEATURES_ENABLE('4.0.0.0') |
| END_OUTLINE_DATA |
| */ |
| Optimization Info: |
| ------------------------------------- |
| T1: |
| table_rows:1 |
| physical_range_rows:1 |
| logical_range_rows:1 |
| index_back_rows:0 |
| output_rows:0 |
| avaiable_index_name:[T1] |
| stats version:0 |
| Plan Type: |
| LOCAL |
| Parameters: |
| :0 => 1 |
| SQL text: |
| ------------------------------------- |
| select * from t1 where c1 > 1 |
| Outline data: |
| ------------------------------------- |
| /*+BEGIN_OUTLINE_DATA FULL(@"SEL$1" "SYS"."T1"@"SEL$1") OPTIMIZER_FEATURES_ENABLE('4.0.0.0')END_OUTLINE_DATA*/ |
| SQL handle: |
| ------------------------------------- |
| 49D6048C041AA8C7E70E2D114250AB99 |
| Plan name: |
| ------------------------------------- |
| 11986391583431335905 |
| Baseline info: |
| ------------------------------------- |
| Origin: AUTO-CAPTURE Accepted: YES Fixed: NO Enabled: YES |
| Plan rows: From plan cahe |
+------------------------------------------------------------------------------------------------------------------+
实时计划
功能介绍
典型的应用场景:当用户在执行一条大SQL时,当前连接执行了很久,用户想要了解查询执行的情况,例如执行计划、执行进程。在这种情况下,由于当前session被大SQL占用,需要开启一条新连接,通过show full processlist命令找到该大SQL所在的session,使用session_id以及display_active_session_plan展示大SQL的执行详情。
相关包函数说明
-- disable real time plan
function display_active_session_plan(
session_id integer default 0,
format varchar2 default 'TYPICAL',
svr_ip varchar2 default null, -- default value: server connected by client
svr_port integer default 0 -- default value: server connected by client
)
return dbms_xplan_type_table;
session_id:用户连接的session id,注意不是proxy session id,是server的session id;
format:计划格式,同上;
svr_ip、svr_port:session所在的节点IP,默认是当前session连接的节点IP;
使用示例(oracle租户)
执行慢SQL:
select count(*) from table(generator(100000)) A, table(generator(10000))B;
连接另外一个会话,使用show processlist命令查询正在执行SQL的session id
show processlist;
+------------+------+--------------------+------+---------+------+--------+---------------------------------------------------------------------------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+------------+------+--------------------+------+---------+------+--------+---------------------------------------------------------------------------+
| 3221675847 | SYS | 11.158.31.44:57841 | SYS | Query | 0 | ACTIVE | show processlist |
| 3221668463 | SYS | 11.158.31.44:57530 | SYS | Query | 2 | ACTIVE | select count(*) from table(generator(100000)) A, table(generator(10000))B |
+------------+------+--------------------+------+---------+------+--------+---------------------------------------------------------------------------+
展示session计划详情
select * from table(dbms_xplan.display_active_session_plan(3221668463));
+--------------------------------------------------------------------------------------------------------------------+
| COLUMN_VALUE |
+--------------------------------------------------------------------------------------------------------------------+
| ============================================================================================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)|REAL.ROWS|REAL.TIME(us)|IO TIME(us)|CPU TIME(us)| |
| -------------------------------------------------------------------------------------------------------------- |
| |0 |SCALAR GROUP BY | |1 |1794 |0 |0 |0 |0 | |
| |1 |└─NESTED-LOOP JOIN CARTESIAN | |39601 |1076 |0 |0 |0 |0 | |
| |2 | ├─FUNCTION_TABLE |A |199 |1 |0 |0 |0 |0 | |
| |3 | └─MATERIAL | |199 |80 |0 |0 |0 |0 | |
| |4 | └─FUNCTION_TABLE |B |199 |1 |0 |0 |0 |0 | |
| ============================================================================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T_FUN_COUNT(*)]), filter(nil), rowset=256 |
| group(nil), agg_func([T_FUN_COUNT(*)]) |
| 1 - output(nil), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 2 - output(nil), filter(nil) |
| value(GENERATOR(cast(:0, BIGINT(-1, 0)))) |
| 3 - output(nil), filter(nil), rowset=256 |
| 4 - output(nil), filter(nil) |
| value(GENERATOR(cast(:1, BIGINT(-1, 0)))) |
+--------------------------------------------------------------------------------------------------------------------+
使用示例(mysql租户)
执行慢SQL:
select count(*) from table(generator(100000)) A, table(generator(10000))B;
连接另外一个会话,使用show processlist命令查询正在执行SQL的session id
show processlist;
+------------+------+--------------------+------+---------+------+--------+---------------------------------------------------------------------------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+------------+------+--------------------+------+---------+------+--------+---------------------------------------------------------------------------+
| 3221675847 | SYS | 11.158.31.44:57841 | SYS | Query | 0 | ACTIVE | show processlist |
| 3221668463 | SYS | 11.158.31.44:57530 | SYS | Query | 2 | ACTIVE | select count(*) from table(generator(100000)) A, table(generator(10000))B |
+------------+------+--------------------+------+---------+------+--------+---------------------------------------------------------------------------+
展示session计划详情
select dbms_xplan.display_active_session_plan(3221668463);
+--------------------------------------------------------------------------------------------------------------------+
| COLUMN_VALUE |
+--------------------------------------------------------------------------------------------------------------------+
| ============================================================================================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)|REAL.ROWS|REAL.TIME(us)|IO TIME(us)|CPU TIME(us)| |
| -------------------------------------------------------------------------------------------------------------- |
| |0 |SCALAR GROUP BY | |1 |1794 |0 |0 |0 |0 | |
| |1 |└─NESTED-LOOP JOIN CARTESIAN | |39601 |1076 |0 |0 |0 |0 | |
| |2 | ├─FUNCTION_TABLE |A |199 |1 |0 |0 |0 |0 | |
| |3 | └─MATERIAL | |199 |80 |0 |0 |0 |0 | |
| |4 | └─FUNCTION_TABLE |B |199 |1 |0 |0 |0 |0 | |
| ============================================================================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([T_FUN_COUNT(*)]), filter(nil), rowset=256 |
| group(nil), agg_func([T_FUN_COUNT(*)]) |
| 1 - output(nil), filter(nil), rowset=256 |
| conds(nil), nl_params_(nil), use_batch=false |
| 2 - output(nil), filter(nil) |
| value(GENERATOR(cast(:0, BIGINT(-1, 0)))) |
| 3 - output(nil), filter(nil), rowset=256 |
| 4 - output(nil), filter(nil) |
| value(GENERATOR(cast(:1, BIGINT(-1, 0)))) |
+--------------------------------------------------------------------------------------------------------------------+