OceanBase SQL 执行计划解读(一)──基础概念

本文分享了OceanBase SQL执行计划的基本概念与解读经验,详细介绍了表访问、索引使用及排序等操作的执行计划特点,并对比了与其他数据库如Oracle的不同之处。

本文分享 OceanBase SQL 执行计划解读经验。

对于熟悉 ORACLE 或 MySQL 的朋友,初次看 OceanBase 的执行计划,会觉得难以理解和接受。相反,只懂一些数据库理论但没有接触过其他数据库的人看 OceanBase 的执行计划反而更容易接受并掌握。这种感觉可能就像武侠小说里说的,得先忘记以前的功夫才能学会新的绝世武功 😄️。等看习惯了OceanBase的SQL执行计划后,自然就适应并体会到自研SQL引擎为何能兼具 OLTP 和 OLAP 两种场景的能力。

执行计划的概念

SQL执行计划简单来说就是SQL执行的路径或者算法,影响SQL的执行性能。差之毫厘,谬以千里。

OceanBase SQL 引擎支持SQL解析,解析后的执行计划会缓存,下次就可以复用。跟传统数据库一样,SQL 文本不一样,执行计划不会复用。此外,如果SQL文本一样,但是执行环境不一样,执行计划也不会复用。目前所知的执行环境包括运行节点IP、会话级别的并行参数,应该还有其他的。所有数据库的SQL执行引擎的成熟度可以从这个小点入手判断。

OceanBase缓存执行计划的两个视图是:gv$plan_cache_plan_stat 和 gv$plan_cache_plan_explain 。这是实际运行使用的执行计划,是更准确的。不过初学的时候看这个比较麻烦,不建议看。所以本文后面只探讨用 EXPLAIN 命令解析的执行计划。

先介绍一些执行计划的大的特点。防止大家跑后面案例时跟我的结果不一样进而不理解。

  • 没有绝对完美正确的执行计划,尤其是 SQL 比较复杂的时候。公说公有理,婆说婆有理。习惯每个问题都有个唯一答案的朋友,可能会不习惯。
  • 同样的SQL,不同 OB 版本的执行计划可能会变化。如果变的更好更合理,那就是产品改进了;如果变的更差更不合理,那可能就是产品缺陷(BUG)。
  • 同样的 SQL 同样的 OB 版本,执行计划也不一定一尘不变。影响执行计划变化的因素可能有数据量(或者统计信息)、会话参数(或变量)、数据分布特点、SQL被路由到的节点等。后两者是 OB 特有的,属于分布式数据库引入的挑战,以后再详细介绍。
  • EXPLAIN 解析的执行计划可能跟实际运行的执行计划不一样,理由同上。
  • SQL 执行计划可以通过 SQL 注释干预,这个需要改SQL。如果SQL不可以改,可以通过大纲(OUTLINE)在线干预。干预的结果可能成功也可能失败。这点以后也详细介绍。

OceanBase 客户端

查看执行计划需要一个好的客户端,这样能将注意力集中在执行计划上。

一是命令行 obclient 命令。obclient 的好处是显示会格式化,当一行结果太长的时候格式会有点不好看,这个时候可以让 SQL 以 \G 替换 结尾时,结果集会列转行展示,可读性更好一些。

二是 OB 官方客户端 ODC。直接选中 SQL,然后点击右上角的 “执行计划”。然后会以表格形式展示执行计划。

三是 开源的 DBeaver 客户端工具。由于 DBeaver 跟 OB还没有紧密适配,所以只能下 EXPLAIN [SQL] 的方式查看执行计划。但是它的 UI 体验非常好。

注意,不管是哪种客户端,建议设置一下事务自动提交(autocommit=on) 或者 每次查看执行计划时自动重连一下会话。

EXPLAIN 命令

EXPLAIN 命令完整的语法是:

{EXPLAIN | DESCRIBE | DESC} 
[BASIC | OUTLINE | EXTENDED | EXTENDED_NOADDR | PARTITIONS | FORMAT = {TRADITIONAL| JSON}] 
{SELECT statement | DELETE statement | INSERT statement | REPLACE statement| UPDATE statement}

学习遵从由简入繁原则,先从默认的 BASIC格式入手。不用指定。FORMAT 有 TRADITIONAL 和 JSON ,默认是 TRADITIONAL ,人可读性好一些。JSON 格式对程序解析比较友好。

先看一个简单的 SQL 执行计划格式。 

EXPLAIN 
SELECT count(*) FROM BMSQL_ITEM 
;

为减少文章图片,我选择用 obclient 展示。

obclient> EXPLAIN
    -> SELECT count(*) FROM BMSQL_ITEM \G
*************************** 1. row ***************************
Query Plan: ===============================================
|ID|OPERATOR       |NAME      |EST. ROWS|COST |
-----------------------------------------------
|0 |SCALAR GROUP BY|          |1        |78754|
|1 | TABLE SCAN    |BMSQL_ITEM|99995    |59653|
===============================================

Outputs & filters:
-------------------------------------
  0 - output([T_FUN_COUNT(*)]), filter(nil),
      group(nil), agg_func([T_FUN_COUNT(*)])
  1 - output([1]), filter(nil),
      access([BMSQL_ITEM.I_ID]), partitions(p0)

1 row in set (0.01 sec)

整个 EXPLAIN 结果是一行。在 OB 内部,这个结果估计是以 JSON 格式储。如下:

{
  "ID": 1,
  "OPERATOR": "GROUP BY",
  "NAME": "GROUP BY",
  "EST.ROWS": 1,
  "COST": 4352454,
  "output": [
    "T_FUN_COUNT(*)"
  ],
  "CHILD_1": {
    "ID": 0,
    "OPERATOR": "TABLE SCAN",
    "NAME": "TABLE SCAN",
    "EST.ROWS": 10000000,
    "COST": 2442330,
    "output": [
      "1"
    ]
  }
}

这个 JSON 内容描述的是一个树,对普通用户可读性不好。所以传统格式的展示分为两部分。第一部分是用表格形式展示执行计划这棵树。每行是一个独立的操作,操作符是 OPERATOR, 操作有 ID。操作展示可能会缩进。缩进表示是内部操作,可以嵌套。执行顺序遵循由内到外,由上到下。操作符支持的内容也是 SQL 引擎成熟度的一个体现。

第一部分说明:

  • OPERATOR : 表示操作算子的名称,TABLE SCAN, 是常用操作算子,表示扫描。
  • NAME: 表示算子操作的对象。可以是表名或者索引名,或者内部临时视图名。需要注意的是如果是扫描主键,展示的依然是表名。因为 OB 里的表和索引的本质都是索引组织表。表数据跟主键索引是一个概念。
  • EST. ROWS:执行当前算子输出的行数,跟统计信息有关。OB里表的统计信息目前只有在集群合并的时候才更新。
  • COST: 执行当前算子预估的成本。COST计算比较复杂,暂时先不深入。

第二部分说明:

第二部分的内容跟第一部分有关,主要是描述第一部分算子的具体信息。有一些公共的信息如下:

  • output : 表示当前算子输出的表达式(也包含列)。
  • filter : 表示当前算子的过滤表达式,nil表示无。如果当前算子是访问存储层,这个过滤表达式可以下推(push)。

常用 SQL 执行计划解读

表访问

表结构:

CREATE TABLE "BMSQL_ITEM" (
  "I_ID" NUMBER(38) NOT NULL,
  "I_NAME" VARCHAR2(24),
  "I_PRICE" NUMBER(5,2),
  "I_DATA" VARCHAR2(50),
  "I_IM_ID" NUMBER(38),
  CONSTRAINT "BMSQL_ITEM_OBPK_1615115887968047" PRIMARY KEY ("I_ID")
);

TABLE GET

EXPLAIN 
SELECT i_id, i_name, I_PRICE FROM BMSQL_ITEM WHERE i_id=10
\G

*************************** 1. row ***************************
Query Plan: ========================================
|ID|OPERATOR |NAME      |EST. RO
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值