ob的执行计划是怎么选择的

想咨询下,下面这个测试,为啥不选择走primary

obclient(root@obmysql)[db1]> CREATE TABLE t1 (
→ c1 varchar(20) NOT NULL ,
→ c2 datetime(3) NOT NULL,
→ c3 int(11) NOT NULL ,
→ PRIMARY KEY (c1, c2, c3),
→ KEY IDX1 (C2, C3)
→ );
Query OK, 0 rows affected (0.046 sec)

obclient(root@obmysql)[db1]> desc select * from t1 where 1=1 and c1 in (‘1.a’, ‘2.b’, ‘3.c’)
→ and c2 between ‘2025-07-31 00:00:00.000’ and ‘2025-07-31 23:00:00.000’ order by c2, c3 limit 0, 10;
±-----------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
±-----------------------------------------------------------------------------------------------------------------------------------------------------+
| ==================================================== |
| |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| |
| ---------------------------------------------------- |
| |0 |TABLE RANGE SCAN|t1(IDX1)|1 |4 | |
| ==================================================== |

Outputs & filters:
0 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c1 IN (‘1.a’, ‘2.b’, ‘3.c’)]), rowset=16
access([t1.c1], [t1.c2], [t1.c3]), partitions(p0)
limit(10), offset(0), is_index_back=false, is_global_index=false, filter_before_indexback[false],
range_key([t1.c2], [t1.c3], [t1.c1]), range(2025-07-31 00:00:00.000000,MIN,MIN ; 2025-07-31 23:00:00.000000,MAX,MAX),
range_cond([t1.c2 >= INTERNAL_FUNCTION(‘2025-07-31 00:00:00.000’, 114, 17)], [t1.c2 <= INTERNAL_FUNCTION(‘2025-07-31 23:00:00.000’, 112, 17)])

±-----------------------------------------------------------------------------------------------------------------------------------------------------+
12 rows in set (0.015 sec)

obclient(root@obmysql)[db1]>

2 个赞

OB 根据代价估算出来的使用主键的代价比使用IDX1的代价要高,所以选择的IDX1,如果把c1 in 换成等于一个值 c1=‘1.a’ ,那么肯定会选择主键

1 个赞

1 个赞

我觉得一是表里数据量不大,二是后面有一个和索引一样的排序。个人感觉ob会更倾向于不要重新排序

1 个赞

我感觉主键更贴切吧,主键的字段,不仅包括条件,后面排序的字段也包括

1 个赞

1 个赞

这个截图也没有走主键吧,主键的算子应该是 table get吧

1 个赞

table get 查询的结果是0条或者1条,显然这个SQL的返回结果不是,使用的是主键的范围扫描,但是也属于主键扫描,另外因为c2是一个范围不是一个值,还有查询条件中也没有C3,所以不会用table get

1 个赞

如果查询条件是 c1=’’ and c2=’’ and c3=’’ 这种情况下算子才会是table get

1 个赞

1 个赞

我这个是空表

1 个赞

我的意思是主键的三个索引字段,都包含在条件里了,而idx1 只有一个 c2,个人感觉针对这些条件 主键的这个索引比idx1索引更好吧

1 个赞

这种条件也没选择走索引

1 个赞


比如这个查询的字段,还有谓词条件,都包含在索引里面了,但还是扫的全表,所以就没太搞懂优化器是怎么进行选择的

1 个赞

在 OceanBase 数据库中,TABLE RANGE SCAN 是一种常见的执行计划算子,用于表示按范围条件从表中检索数据的操作。当涉及到主键扫描时,TABLE RANGE SCAN 通常用于根据主键范围进行数据检索。以下是一些关键点,帮助您更好地理解主键扫描 TABLE RANGE SCAN 的作用和特点:

主键扫描 vs 全表扫描:

主键扫描:当查询条件中包含主键范围时,OceanBase 会选择 TABLE RANGE SCAN 算子进行主键范围扫描,而不是全表扫描。这种方式通常比全表扫描更高效,因为它可以直接利用主键索引来快速定位数据
全表扫描:如果查询条件中没有主键范围,或者优化器认为全表扫描的代价更低,那么可能会选择全表扫描
执行计划中的 TABLE RANGE SCAN:

OPERATOR:在执行计划中,TABLE RANGE SCAN 表示范围扫描操作,会返回 0 行或多行数据

你这边先弄明白一些概念性的东西

1 个赞

另外还有一个东西,主键是包含了所有的字段,但是你的order by 的字段是 c2,c3 如果使用主键扫描是需要对查询结果进行排序的,这个也会计算代价

1 个赞

我在ORACLE数据库上做了测试,同样这个语句执行计划跟OB是一致的

1 个赞