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

相关推荐
翻斗包菜2 分钟前
第 03 章 Python 操作 MySQL 数据库实战全解
数据库·python·mysql
SPC的存折5 分钟前
1、MySQL故障排查与运维案例
linux·运维·服务器·数据库·mysql
小臭希8 分钟前
Redis(NoSQL数据库,Linux-Ubuntu环境下)
数据库·redis·缓存
cdcdhj9 分钟前
在window下将Mongodb单机改为副本集,只用于测试环境,实际上并没有增加真的副本集
数据库·mongodb
xcjbqd014 分钟前
如何修改Oracle服务器默认的日期格式_NLS_DATE_FORMAT全局配置
jvm·数据库·python
HealthScience14 分钟前
SpliceVarDB数据集说明
数据库·oracle
倔强的石头_20 分钟前
表空间自动目录创建与存储管理实践:参数化配置与性能优化
数据库
white-persist24 分钟前
【vulhub spring CVE-2018-1270】CVE-2018-1270 Spring Messaging 远程命令执行漏洞 完整复现详细分析解释
java·服务器·网络·数据库·后端·python·spring
鬼先生_sir32 分钟前
MySQL进阶-事务与锁机制
数据库·mysql·mvcc
treacle田1 小时前
达梦数据库-达梦数据库中link链接访问远程Sql Sever-记录总结
数据库·达梦-sqlserver