OceanBase 分区裁剪(Partition Pruning)原理解读
分区裁剪(Partition Pruning)原理与应用详解
参考OceanBase v3.2.3 官方文档:分区裁剪
什么是分区裁剪?
分区裁剪(Partition Pruning)是数据库中对分区表进行查询优化的一种重要手段。通过该功能,数据库优化器可以避免访问与查询无关的分区,从而大幅提升 SQL 查询的执行效率。
当用户访问分区表时,往往只需要访问其中部分分区。优化器根据 SQL 中给定的条件与表的分区信息,自动过滤掉不需要访问的分区,这一过程就称为分区裁剪。
为什么需要分区裁剪?
分区表通常将数据按一定规则划分为多个分区存储。在执行查询时,如果无法提前确定所需分区,就可能需要扫描所有分区,导致查询效率低下。而通过分区裁剪,查询仅需访问特定分区,显著减少 I/O 操作和计算资源消耗,提升查询性能。
分区裁剪示例
我们通过一个简单的示例来说明分区裁剪的作用:
CREATE TABLE tbl1 (col1 INT,col2 INT
) PARTITION BY HASH(col1) PARTITIONS 5;SELECT * FROM tbl1 WHERE col1 = 1;
在这个例子中,col1 = 1
的数据全部位于第 1 号分区(p1),因此只需要访问该分区,而无需访问其他分区。
通过 EXPLAIN
查看执行计划,可以确认分区裁剪的效果:
EXPLAIN SELECT * FROM tbl1 WHERE col1 = 1 \G
输出结果如下:
*************************** 1. row ***************************
Query Plan: ===================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
-----------------------------------
|0 |TABLE SCAN|TBL1|990 |383 |
===================================Outputs & filters:
-------------------------------------0 - output([TBL1.COL1], [TBL1.COL2]), filter(nil),access([TBL1.COL1], [TBL1.COL2]), partitions(p1)
从执行计划中可以看到,仅分区 p1
被访问,说明分区裁剪已生效。
一级分区裁剪原理
Hash/List 分区
分区裁剪根据 WHERE 子句中的条件计算分区列的值,进而判断需要访问哪些分区。如果分区条件是一个表达式,且该表达式以整体形式出现在等值条件中,也可以进行分区裁剪。
例如:
CREATE TABLE t1 (c1 INT, c2 INT
) PARTITION BY HASH(c1 + c2) PARTITIONS 5;EXPLAIN SELECT * FROM t1 WHERE c1 + c2 = 1 \G
*************************** 1. row ***************************
Query Plan: ===================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
-----------------------------------
|0 |TABLE SCAN|t1 |5 |1303|
===================================Outputs & filters:
-------------------------------------0 - output([t1.c1], [t1.c2]), filter([t1.c1 + t1.c2 = 1]),access([t1.c1], [t1.c2]), partitions(p1)
执行计划输出中可以看到仅访问了分区 p1
。
Range 分区
Range 分区的裁剪是通过 WHERE 子句中分区键的范围与表定义的分区范围求交集,从而确定需要访问的分区。
需要注意的是,如果分区条件是一个函数,且查询条件是一个范围,则可能无法进行分区裁剪。例如:
CREATE TABLE t1 (c1 INT,c2 INT
) PARTITION BY RANGE(c1 + 1) (PARTITION p0 VALUES LESS THAN(100),PARTITION p1 VALUES LESS THAN(200)
);EXPLAIN SELECT * FROM t1 WHERE c1 < 150 AND c1 > 110 \G
*************************** 1. row ***************************
Query Plan: ============================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
--------------------------------------------
|0 |EXCHANGE IN DISTR | |19 |1410|
|1 | EXCHANGE OUT DISTR| |19 |1303|
|2 | TABLE SCAN |t1 |19 |1303|
============================================Outputs & filters:
-------------------------------------0 - output([t1.c1], [t1.c2]), filter(nil)1 - output([t1.c1], [t1.c2]), filter(nil)2 - output([t1.c1], [t1.c2]), filter([t1.c1 < 150], [t1.c1 > 110]),access([t1.c1], [t1.c2]), partitions(p[0-1])
此时无法进行分区裁剪,需访问所有分区(p0 和 p1)。
而在等值查询中,分区裁剪仍可生效:
EXPLAIN SELECT * FROM t1 WHERE c1 = 150 \G
*************************** 1. row ***************************
Query Plan: ===================================
|ID|OPERATOR |NAME|EST. ROWS|COST|
-----------------------------------
|0 |TABLE SCAN|t1 |1 |1303|
===================================Outputs & filters:
-------------------------------------0 - output([t1.c1], [t1.c2]), filter([t1.c1 = 150]),access([t1.c1], [t1.c2]), partitions(p1)
此时仅需访问分区 p1
。
二级分区裁剪原理
对于二级分区,分区裁剪分为两步:
- 根据一级分区键确定一级分区;
- 根据二级分区键确定二级分区。
最终访问的物理分区是一级和二级分区裁剪结果的乘积。
例如:
CREATE TABLE tbl2_rr (col1 INT,col2 INT
)
PARTITION BY RANGE(col1)
SUBPARTITION BY RANGE(col2)
SUBPARTITION TEMPLATE (SUBPARTITION sp0 VALUES LESS THAN(1000),SUBPARTITION sp1 VALUES LESS THAN(2000)
) (PARTITION p0 VALUES LESS THAN(100),PARTITION p1 VALUES LESS THAN(200)
);EXPLAIN SELECT * FROM tbl2_rr
WHERE (col1 = 1 OR col1 = 2) AND (col2 > 101 AND col2 < 150) \G
*************************** 1. row ***************************
Query Plan: ======================================
|ID|OPERATOR |NAME |EST. ROWS|COST|
--------------------------------------
|0 |TABLE SCAN|TBL2_RR|99 |53 |
======================================Outputs & filters:
-------------------------------------0 - output([TBL2_RR.COL1], [TBL2_RR.COL2]), filter(nil),access([TBL2_RR.COL1], [TBL2_RR.COL2]), partitions(p0sp0)1 row in set
执行计划显示仅访问物理分区 p0sp0
,说明一二级分区裁剪均生效。
总结
分区裁剪是分区表查询优化中的关键机制,通过减少不必要的分区访问,显著提升查询性能。在使用时应注意:
- 尽量在查询条件中明确分区键的值或范围;
- 对于表达式作为分区键的情况,确保条件为等值查询以利于裁剪;
- 二级分区裁剪是逐级进行的,最终访问分区为两级分区裁剪结果的乘积。
合理设计分区键和查询条件,可以充分发挥分区裁剪的优势,优化数据库查询性能。
注意:本文示例基于 OceanBase 数据库语法,但分区裁剪的原理在不同数据库系统中基本一致,可供广大数据库开发者与运维人员参考。