codecamp

OceanBase 基于代价的路径选择

在基于规则的路径选择之后,如果存在多个可以选择的路径,那么 OceanBase 数据库会计算每个路径的代价,并从中选择代价最小的路径作为最终选择的路径。

OceanBase 数据库的代价模型考虑了 CPU 代价(比如处理一个谓词的 CPU 开销)和 IO 代价(比如顺序、随机读取宏块和微块的代价),CPU 代价和 IO 代价最终相加得到一个总的代价。

在 OceanBase 数据库中,每个访问路径的代价会在执行计划中都会展示出来。如下例所示:

obclient>CREATE TABLE t1(a INT PRIMARY KEY, b INT, c INT, INDEX k1(b));
Query OK, 0 rows affected (0.35 sec)

/*主表路径的代价*/
obclient>EXPLAIN SELECT/*+INDEX(t1 PRIMARY)*/ * FROM t1 WHERE b < 10;
+-----------------------------------------------------------------+
| Query Plan                                                                              |
+-----------------------------------------------------------------+
| ===================================
|ID|OPERATOR  |NAME|EST. ROWS|COST|
-----------------------------------
|0 |TABLE SCAN|t1  |200      |622 |
===================================

Outputs & filters:
-------------------------------------
  0 - output([t1.a], [t1.b], [t1.c]), filter([t1.b < 10]),
      access([t1.b], [t1.a], [t1.c]), partitions(p0)

/* k1 路径的代价*/
obclient> EXPLAIN SELECT/*+INDEX(t1 k1)*/ * FROM t1 WHERE b < 10;
+--------------------------------------------------------------------+
| Query Plan                                                                                   |
+--------------------------------------------------------------------+
| =====================================
|ID|OPERATOR  |NAME  |EST. ROWS|COST|
-------------------------------------
|0 |TABLE SCAN|t1(k1)|200      |1114|
=====================================

Outputs & filters:
-------------------------------------
  0 - output([t1.a], [t1.b], [t1.c]), filter(nil),
      access([t1.b], [t1.a], [t1.c]), partitions(p0)

对于一个访问路径,它的代价主要由扫描访问路径的代价和回表的代价两部分组成。如果一个访问路径不需要回表,那么就没有回表的代价。

在 OceanBase 数据库中,访问路径的代价取决于很多因素,比如扫描的行数、回表的行数、投影的列数和谓词的个数等。但是对于访问路径来说,代价在很大程度上取决于行数,所以在下面的示例分析中,从行数这个维度来介绍这两部分的代价。

  • 扫描访问路径的代价

    扫描访问路径的代价跟扫描的行数成正比,理论上来说扫描的行数越多,执行时间就会越久。对于一个访问路径,query range 决定了需要扫描的范围,从而决定了需要扫描的行数。Query range 的扫描是顺序 IO。

  • 回表的代价

    回表的代价跟回表的行数也也是正相关的,回表的行数越多(回表的行数是指满足所有能在索引上执行的谓词的行数),执行时间就会越长。回表的扫描是随机 IO,所以回表一行的代价会比 query range 扫描一行的代价高很多。

当分析一个访问路径的性能的时候,可以从上面两个因素入手,获取通过 query range 扫描的行数以及回表的行数。这两个行数通常可以通过执行 SQL 语句来获取。

如下例所示,对于查询 SELECT * FROM t1 WHERE c2 > 20 AND c2 < 800 AND c3 < 200,索引 k1 的访问路径是,首先通常计划展示来获取用来抽取 query range 的谓词,谓词 c2 > 20 AND c2 < 800 用来抽取 query range,谓词 c3 < 200 被当成回表前的谓词。那么可以使用如下两个查询来检查 query range 抽取的行数以及回表之后的行数。

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

obclient>EXPLAIN EXTENDED_NOADDR SELECT/*+INDEX(t1 k1)*/ * FROM t1 WHERE 
      c2 > 20 AND c2 < 800 AND c3 < 200;
+--------------------------------------------------------------+
| Query Plan                                                                          |
+--------------------------------------------------------------+
| =====================================
|ID|OPERATOR  |NAME  |EST. ROWS|COST|
-------------------------------------
|0 |TABLE SCAN|t1(k1)|156      |1216|
=====================================

Outputs & filters:
-------------------------------------
  0 - output([t1.c1], [t1.c2], [t1.c3], [t1.c4], [t1.c5]), filter([t1.c3 < 200]),
      access([t1.c2], [t1.c3], [t1.c1], [t1.c4], [t1.c5]), partitions(p0),
      is_index_back=true, filter_before_indexback[true],
      range_key([t1.c2], [t1.c3], [t1.c1]), range(20,MAX,MAX ; 800,MIN,MIN),
      range_cond([t1.c2 > 20], [t1.c2 < 800])

/*query range 扫描的行数*/
obclient>SELECT/*+INDEX(t1 k1)*/ COUNT(*) FROM t1 WHERE c2 > 20 AND c2 < 800;
+----------+
| count(*) |
+----------+
|      779 |
+----------+
1 row in set (0.02 sec)

/* 回表的行数*/
obclient> SELECT/*+INDEX(t1 k1)*/ COUNT(*) FROM t1 WHERE c2 > 20 AND c2 < 800
      AND c3 < 200;
+----------+
| count(*) |
+----------+
|      179 |
+----------+
1 row in set (0.01 sec)
OceanBase 基于规则的路径选择
OceanBase 联接算法概述
温馨提示
下载编程狮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; }