OceanBase 分区裁剪(Partition Pruning)原理解读

分区裁剪(Partition Pruning)原理与应用详解

参考OceanBase v3.2.3 官方文档:分区裁剪

什么是分区裁剪?

分区裁剪(Partition Pruning)是数据库中对分区表进行查询优化的一种重要手段。通过该功能,数据库优化器可以避免访问与查询无关的分区,从而大幅提升 SQL 查询的执行效率。

当用户访问分区表时,往往只需要访问其中部分分区。优化器根据 SQL 中给定的条件与表的分区信息,自动过滤掉不需要访问的分区,这一过程就称为分区裁剪。


为什么需要分区裁剪?

分区表通常将数据按一定规则划分为多个分区存储。在执行查询时,如果无法提前确定所需分区,就可能需要扫描所有分区,导致查询效率低下。而通过分区裁剪,查询仅需访问特定分区,显著减少 I/O 操作和计算资源消耗,提升查询性能。


分区裁剪示例

我们通过一个简单的示例来说明分区裁剪的作用:

sql 复制代码
CREATE TABLE tbl1 (
    col1 INT,
    col2 INT
) PARTITION BY HASH(col1) PARTITIONS 5;

SELECT * FROM tbl1 WHERE col1 = 1;

在这个例子中,col1 = 1 的数据全部位于第 1 号分区(p1),因此只需要访问该分区,而无需访问其他分区。

通过 EXPLAIN 查看执行计划,可以确认分区裁剪的效果:

sql 复制代码
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 子句中的条件计算分区列的值,进而判断需要访问哪些分区。如果分区条件是一个表达式,且该表达式以整体形式出现在等值条件中,也可以进行分区裁剪。

例如:

sql 复制代码
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 子句中分区键的范围与表定义的分区范围求交集,从而确定需要访问的分区。

需要注意的是,如果分区条件是一个函数,且查询条件是一个范围,则可能无法进行分区裁剪。例如:

sql 复制代码
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)。

而在等值查询中,分区裁剪仍可生效:

sql 复制代码
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


二级分区裁剪原理

对于二级分区,分区裁剪分为两步:

  1. 根据一级分区键确定一级分区;
  2. 根据二级分区键确定二级分区。

最终访问的物理分区是一级和二级分区裁剪结果的乘积。

例如:

sql 复制代码
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 数据库语法,但分区裁剪的原理在不同数据库系统中基本一致,可供广大数据库开发者与运维人员参考。

相关推荐
Jayyih3 小时前
嵌入式系统学习Day35(sqlite3数据库)
数据库·学习·sqlite
得意霄尽欢5 小时前
Redis之底层数据结构
数据结构·数据库·redis
hsjkdhs6 小时前
MySQL 数据类型与运算符详解
数据库·mysql
爱吃烤鸡翅的酸菜鱼7 小时前
【Redis】常用数据结构之Hash篇:从常用命令到使用场景详解
数据结构·数据库·redis·后端·缓存·哈希算法
李少兄7 小时前
IntelliJ IDEA 启动项目时配置端口指南
数据库·sql·intellij-idea
NineData7 小时前
NineData云原生智能数据管理平台新功能发布|2025年8月版
数据库·mongodb·云原生·数据库管理工具·ninedata·数据库迁移·数据复制
白云如幻7 小时前
【Java】QBC检索和本地SQL检索
java·数据库·sql
勘察加熊人8 小时前
python将pdf转txt,并切割ai
数据库·python·pdf
不良人天码星8 小时前
Redis单线程模型为什么快?
数据库·redis·缓存
RestCloud9 小时前
ETL 不只是数据搬运工:如何实现智能转换与清洗?
数据库·api