codecamp

OceanBase TABLE SCAN

TABLE SCAN 算子是存储层和 SQL 层的接口,用于展示优化器选择哪个索引来访问数据。

在 OceanBase 数据库中,对于普通索引,索引的回表逻辑是封装在 TABLE SCAN 算子中的;而对于全局索引,索引的回表逻辑由 TABLE LOOKUP 算子完成。

示例:含 TABLE SCAN 算子的执行计划

obclient>CREATE TABLE t1(c1 INT PRIMARY KEY, c2 INT, c3 INT, c4 INT, 
      INDEX k1(c2,c3));
Query OK, 0 rows affected (0.09 sec)

Q1:
obclient>EXPLAIN EXTENDED SELECT * FROM t1 WHERE c1 = 1\G;
*************************** 1. row ***************************
Query Plan: 
| ==================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
----------------------------------
|0 |TABLE GET|t1  |1        |53  |
==================================
Outputs & filters:
-------------------------------------
  0 - output([t1.c1(0x7f22fbe69340)], [t1.c2(0x7f22fbe695c0)], [t1.c3(0x7f22fbe69840)], [t1.c4(0x7f22fbe69ac0)]), filter(nil),
      access([t1.c1(0x7f22fbe69340)], [t1.c2(0x7f22fbe695c0)], [t1.c3(0x7f22fbe69840)], [t1.c4(0x7f22fbe69ac0)]), partitions(p0),
      is_index_back=false,
      range_key([t1.c1(0x7f22fbe69340)]), range[1 ; 1],
      range_cond([t1.c1(0x7f22fbe69340) = 1(0x7f22fbe68cf0)])

Q2:
obclient>EXPLAIN EXTENDED SELECT * FROM t1 WHERE c2 < 1 AND c3 < 1 AND
         c4 < 1\G;
*************************** 1. row ***************************
Query Plan: 
| ======================================
|ID|OPERATOR  |NAME  |EST. ROWS|COST |
--------------------------------------
|0 |TABLE SCAN|t1(k1)|100      |12422|
======================================

Outputs & filters:
-------------------------------------
  0 - output([t1.c1(0x7f22fbd1e220)], [t1.c2(0x7f227decec40)], [t1.c3(0x7f227decf9b0)], [t1.c4(0x7f22fbd1dfa0)]), filter([t1.c3(0x7f227decf9b0) < 1(0x7f227decf360)], [t1.c4(0x7f22fbd1dfa0) < 1(0x7f22fbd1d950)]),
      access([t1.c2(0x7f227decec40)], [t1.c3(0x7f227decf9b0)], [t1.c4(0x7f22fbd1dfa0)], [t1.c1(0x7f22fbd1e220)]), partitions(p0),
      is_index_back=true, filter_before_indexback[true,false],
      range_key([t1.c2(0x7f227decec40)], [t1.c3(0x7f227decf9b0)], [t1.c1(0x7f22fbd1e220)]), 
      range(NULL,MAX,MAX ; 1,MIN,MIN),
      range_cond([t1.c2(0x7f227decec40) < 1(0x7f227dece5f0)])

上述示例中,执行计划展示中的 outputs & filters 详细展示了 TABLE SCAN 算子的输出信息如下:

信息名称

含义

operator

TABLE SCAN 算子的 operator 有两种形式:TABLE SCAN 和 TABLE GET。

  • TABLE SCAN:属于范围扫描,会返回 0 行或者多行数据。

  • TABLE GET:直接用主键定位,返回 0 行或者 1 行数据。

name

选择用哪个索引来访问数据。选择的索引的名字会跟在表名后面,如果没有索引的名字,则说明执行的是主表扫描。

这里需要注意,在 OceanBase 数据库中,主表和索引的组织结构是一样的,主表本身也是一个索引。

output

该算子的输出列。

filter

该算子的过滤谓词。

由于示例中 TABLE SCAN 算子没有设置 filter,所以为 nil。

partitions

查询需要扫描的分区。

is_index_back

该算子是否需要回表。

例如,在 Q1 查询中,因为选择了主表,所以不需要回表。在 Q2 查询中,索引列是 (c2,c3,c1), 由于查询需要返回 c4 列,所以需要回表。

filter_before_indexback

与每个 filter 对应,表明该 filter 是可以直接在索引上进行计算,还是需要索引回表之后才能计算。

例如,在 Q2 查询中,filter c3 < 1 可以直接在索引上计算,能减少回表数量;filter c4 < 1 需要回表取出 c4 列之后才能计算。

range_key/range/range_cond

  • range_key:索引的 rowkey 列。

  • range:索引开始扫描和结束扫描的位置。判断是否是全表扫描需要关注 range 的范围。例如,对于一个 rowkey 有三列的场景,range(MIN,MIN, MIN ; MAX, MAX, MAX)代表的就是真正意义上的全表扫描。

  • range_cond:决定索引开始扫描和结束扫描位置的相关谓词。

OceanBase SQL执行计划简介
OceanBase TABLE LOOKUP
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

OceanBase 控制台指南

OceanBase ODC 使用指南

OceanBase Web 版 ODC

OceanBase 客户端版 ODC

OceanBase Connector/J 开发者指南

OceanBase 什么是OceanBase Connector/J

OceanBase SQL 参考(MySQL 模式)

OceanBase SQL 参考(Oracle 模式)

OceanBase 基本元素

OceanBase 数据库对象

OceanBase 函数

OceanBase 单行函数

OceanBase 返回数字的字符串函数

OceanBase 通用比较函数

OceanBase 编码解码函数

OceanBase SQL 调优指南

OceanBase 相关协议

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }