在分布式查询场景下,当两张或多张分区表 JOIN 时,如果它们分区规则完全一样,可以考虑创建表组,使不同表的相同分区在同一节点上。
如下图所示,分区表 A 和 分区表 B 分区规则完全一样,将表 A 和 分区表 B 放在同一表组后,两表的同名分区 P1 都在节点 B 上,两表的同名分区 P2 都在节点 A 上,依此类推,这样可以避免在分布式查询时多个数据库节点间进行数据的交换,以提高性能。

本文以 OceanBase 数据库 V4.2.1 BP10 -1-1 集群 MySQL 模式分区规则完全一样的两个二级分区表为例,在 Primary Zone 打散 (e.g. zone1,zone2,zone3) 的情况下,介绍 OceanBase 数据库 V4.x ADAPTIVE 表组使用示例和如何手动触发负载均衡任务以使表组中的同名分区分布在同一节点上。
详细说明
Primary Zone 是否打散可以通过如下 SQL 查询 ,primary_zone 为 zone1,zone2,zone3 则表示打散,zone1;zone2;zone3 则表示未打散。
mysql> SELECT tenant_id,tenant_name,tenant_type,primary_zone FROM dba_ob_tenants ORDER BY tenant_id DESC;
+-----------+-------------+-------------+-------------------+
| tenant_id | tenant_name | tenant_type | primary_zone |
+-----------+-------------+-------------+-------------------+
| 1074 | obmysql | USER | zone1,zone2,zone3 |
+-----------+-------------+-------------+-------------------+
1 row in set (0.08 sec)
根据不同情况,可以通过如下两种方式将表加入表组。
方式一 创建表时指定表组
方法优势:
创建同一表组的分区规则完全一样的多个分区表后,立即自动进行负载均衡,且同名的二级分区在同一数据库节点上,不需要后续进行任何手动操作。
方法劣势:
需要在创建表时指定表组,不灵活。
测试用例如下。
创建表组 tg1。
CREATE TABLEGROUP tg1 SHARDING='ADAPTIVE';
查询表组 tg1。
SHOW TABLEGROUPS WHERE tablegroup_name = 'TG1';
查询表组结果如下。
mysql> SHOW TABLEGROUPS WHERE tablegroup_name = 'TG1';
+-----------------+------------+---------------+----------+
| Tablegroup_name | Table_name | Database_name | Sharding |
+-----------------+------------+---------------+----------+
| tg1 | NULL | NULL | ADAPTIVE |
+-----------------+------------+---------------+----------+
1 row in set (0.04 sec)
接下来在表组中加入表。
MySQL 租户下创建分区表 (指定表组 (TABLEGROUP = tg1) ) 语法如下。
CREATE TABLE sales1 (
sale_id INT NOT NULL,
region INT,
product INT,
quantity INT,
sale_date DATE,
PRIMARY KEY (sale_id, region,product)
)
TABLEGROUP = tg1
PARTITION BY LIST (region)
SUBPARTITION BY HASH (product) SUBPARTITIONS 3 (
PARTITION p0 VALUES IN (0),
PARTITION p1 VALUES IN (1)
);
CREATE TABLE sales2 (
sale_id INT NOT NULL,
region INT,
product INT,
quantity INT,
sale_date DATE,
PRIMARY KEY (sale_id, region,product)
)
TABLEGROUP = tg1
PARTITION BY LIST (region)
SUBPARTITION BY HASH (product) SUBPARTITIONS 3 (
PARTITION p0 VALUES IN (0),
PARTITION p1 VALUES IN (1)
);
Oracle 租户下创建分区表 (指定表组 (TABLEGROUP = tg1) ) 语法如下。
CREATE TABLE sales1 (
sale_id NUMBER NOT NULL,
region NUMBER,
product NUMBER,
quantity NUMBER,
sale_date DATE,
PRIMARY KEY (sale_id, region, product)
)
TABLEGROUP = tg1
PARTITION BY LIST (region)
SUBPARTITION BY HASH (product) SUBPARTITIONS 3 (
PARTITION p0 VALUES (0),
PARTITION p1 VALUES (1)
);
...
在 MySQL 租户创建分区表后查询表组,结果如下。
mysql> SHOW TABLEGROUPS WHERE tablegroup_name = 'TG1';
+-----------------+------------+---------------+----------+
| Tablegroup_name | Table_name | Database_name | Sharding |
+-----------------+------------+---------------+----------+
| tg1 | sales1 | test | ADAPTIVE |
| tg1 | sales2 | test | ADAPTIVE |
+-----------------+------------+---------------+----------+
2 rows in set (0.05 sec)
在 MySQL 租户 oceanbase 数据库通过如下 SQL 查询各分区 LEADER 分布。
SELECT
table_name,
table_id,
object_id,
partition_name,
subpartition_name,
zone,
svr_ip,
role,
tablet_id,
ls_id
FROM
dba_ob_table_locations
WHERE
role = 'LEADER'
-- AND database_name = 'test'
AND lower(table_name) IN ('sales1', 'sales2')
ORDER BY
partition_name,
subpartition_name,
table_name,
zone,
svr_ip,
svr_port;
从如下查询结果可以看出,两张分区表同名的 subpartition (如 p0sp0 ) 都在同一节点上。

方法二 创建表后加入表组
方法优势:
不需要在创建表时指定表组,通过修改表所在的表组,可以在已有数据库创建表组进行分布式查询优化,
方法劣势:
将分区规则完全一样的多个分区表加入同一表组后,不会立即自动进行负载均衡,一般需要进行手动触发负载均衡任务,且手动触发方式依赖数据库具体版本。
测试用例如下。
MySQL 租户下创建两个分区规则完全一样的二级分区表。
CREATE TABLE sales11 (
sale_id INT NOT NULL,
region INT,
product INT,
quantity INT,
sale_date DATE,
PRIMARY KEY (sale_id, region,product)
)
PARTITION BY LIST (region)
SUBPARTITION BY HASH (product) SUBPARTITIONS 3 (
PARTITION p0 VALUES IN (0),
PARTITION p1 VALUES IN (1)
);
CREATE TABLE sales12 (
sale_id INT NOT NULL,
region INT,
product INT,
quantity INT,
sale_date DATE,
PRIMARY KEY (sale_id, region,product)
)
PARTITION BY LIST (region)
SUBPARTITION BY HASH (product) SUBPARTITIONS 3 (
PARTITION p0 VALUES IN (0),
PARTITION p1 VALUES IN (1)
);
在 MySQL 租户 oceanbase 数据库通过如下 SQL 查询各分区 LEADER 分布。
SELECT
table_name,
table_id,
object_id,
partition_name,
subpartition_name,
zone,
svr_ip,
role,
tablet_id,
ls_id
FROM
dba_ob_table_locations
WHERE
role = 'LEADER'
-- AND database_name = 'test'
AND lower(table_name) IN ('sales1', 'sales2')
ORDER BY
partition_name,
subpartition_name,
table_name,
zone,
svr_ip,
svr_port;
从如下查询结果可以看出,两张分区表同名的 subpartition (如 p0sp0 ) 不在同一节点上。

接下来创建表组。
CREATE TABLEGROUP tg11 SHARDING='ADAPTIVE';
查询表组 tg11。
SHOW TABLEGROUPS WHERE tablegroup_name = 'tg11';
将表加入表组有两种方式:
方式一 通过 ALTER TABLE 语句。
ALTER TABLE sales11 TABLEGROUP tg11;
ALTER TABLE sales12 TABLEGROUP tg11;
方式二 通过 ALTER TABLEGROUP 语句。
ALTER TABLEGROUP tg11 ADD sales11,sales12;
注:通过 ALTER TABLEGROUP 语句仅支持增加表到表组,不支持在表组中去掉表。
将两个分区表加入表组执行过程如下。
mysql> CREATE TABLEGROUP tg11 SHARDING='ADAPTIVE';
Query OK, 0 rows affected (0.12 sec)
mysql> SHOW TABLEGROUPS WHERE tablegroup_name = 'tg11';
+-----------------+------------+---------------+----------+
| Tablegroup_name | Table_name | Database_name | Sharding |
+-----------------+------------+---------------+----------+
| tg11 | NULL | NULL | ADAPTIVE |
+-----------------+------------+---------------+----------+
1 row in set (0.06 sec)
mysql> ALTER TABLEGROUP tg11 ADD sales11,sales12;
Query OK, 0 rows affected (0.46 sec)
mysql> SHOW TABLEGROUPS WHERE tablegroup_name = 'tg11';
+-----------------+------------+---------------+----------+
| Tablegroup_name | Table_name | Database_name | Sharding |
+-----------------+------------+---------------+----------+
| tg11 | sales11 | test | ADAPTIVE |
| tg11 | sales12 | test | ADAPTIVE |
+-----------------+------------+---------------+----------+
2 rows in set (0.04 sec)
此时在 MySQL 租户 oceanbase 数据库通过如下 SQL 查询各分区 LEADER 分布。
SELECT
table_name,
table_id,
object_id,
partition_name,
subpartition_name,
zone,
svr_ip,
role,
tablet_id,
ls_id
FROM
dba_ob_table_locations
WHERE
role = 'LEADER'
-- AND database_name = 'test'
AND lower(table_name) IN ('sales11', 'sales12')
ORDER BY
partition_name,
subpartition_name,
table_name,
zone,
svr_ip,
svr_port;
从如下查询结果可以看出,两张分区表同名的 subpartition (如 p0sp0 ) 仍不在同一节点上,需要根据下面步骤手动触发负载均衡任务。

手动触发负载均衡任务
采用方法二创建表后加入表组,不会立即自动进行负载均衡,一般需要进行手动触发负载均衡任务,且手动触发方式依赖数据库具体版本。
首先,在用户租户下查询,当如下参数均为 True 时才会进行正常的分区均衡操作。
SHOW PARAMETERS LIKE 'enable_rebalance';
SHOW PARAMETERS LIKE 'enable_transfer';
然后查看数据库版本,任意用户 (MySQL 模式或 Oracle 模式) 登录通过如下 SQL 查询。
SHOW VARIABLES LIKE '%version_comment%';
根据不同 OceanBase 数据库版本,有如下两种手动触发负载均衡方法。
手动触发负载均衡方法一
适用版本:OceanBase 数据库 V4.2.1 - V4.2.1 BP8, OceanBase 数据库 V4.2.2.x, OceanBase 数据库 V4.2.3.x, OceanBase 数据库 V4.3.0 - V4.3.5
当分区均衡调度周期参数 partition_balance_schedule_interval 默认为 2h 时,将 partition_balance_schedule_interval 修改为 20s ,分区均衡调度完成后再修改为原来的值。
SHOW PARAMETERS LIKE 'partition_balance_schedule_interval';
ALTER SYSTEM SET partition_balance_schedule_interval = '20s';
手动触发负载均衡方法二
适用版本:OceanBase 数据库 V4.2.1 BP9 - V4.2.1 BP10, OceanBase 数据库 V4.2.4.x, OceanBase 数据库 V4.2.5.x。
CALL dbms_balance.trigger_partition_balance();
注 1: OceanBase 数据库 V4.2.1 BP9 和 OceanBase 数据库 V4.2.4 起,partition_balance_schedule_interval 默认值从 2h 变为 0, 不再建议通过配置项 partition_balance_schedule_interval 来控制分区均衡,新增手动触发分区均衡的方法 dbms_balance.trigger_partition_balance() ,并将定时分区均衡任务 SCHEDULED_TRIGGER_PARTITION_BALANCE 默认开启。
注 2: 对于从其他版本升级至 OceanBase 数据库 V4.2.1 BP9 - V4.2.1 BP10 或 OceanBase 数据库 V4.2.4.x/V4.2.5.x 的场景,已有用户租户 partition_balance_schedule_interval 保持不变,分区均衡任务依赖租户级配置项 partition_balance_schedule_interval 控制。
注 3: 对于 OceanBase 数据库 V4.3 版本,截至 OceanBase 数据库 V4.3.5,仍通过配置项 partition_balance_schedule_interval 来控制分区均衡。
手动触发负载均衡后,可以通过如下 SQL 查询负载均衡任务,参见:[负载均衡任务查询]。
SELECT
job_id,
create_time,
balance_strategy,
job_type,
target_unit_num,
target_primary_zone_num,
status
FROM
dba_ob_balance_jobs
ORDER BY
create_time DESC;
SELECT * FROM dba_ob_balance_tasks ORDER BY job_id DESC, task_id DESC\G
SELECT * FROM dba_ob_transfer_tasks ORDER BY balance_task_id desc,task_id DESC\G
SELECT
job_id,
create_time,
finish_time,
balance_strategy,
job_type,
target_unit_num,
target_primary_zone_num,
status
FROM
dba_ob_balance_job_history
ORDER BY
create_time DESC;
SELECT * FROM dba_ob_balance_task_history ORDER BY job_id DESC, task_id DESC\G
SELECT * FROM dba_ob_transfer_task_history ORDER BY balance_task_id desc,task_id DESC\G
此时在 MySQL 租户 oceanbase 数据库通过如下 SQL 查询各分区 LEADER 分布。
SELECT
table_name,
table_id,
object_id,
partition_name,
subpartition_name,
zone,
svr_ip,
role,
tablet_id,
ls_id
FROM
dba_ob_table_locations
WHERE
role = 'LEADER'
-- AND database_name = 'test'
AND lower(table_name) IN ('sales11', 'sales12')
ORDER BY
partition_name,
subpartition_name,
table_name,
zone,
svr_ip,
svr_port;
从如下查询结果可以看出,两张分区表同名的 subpartition (如 p0sp0 ) 在同一节点上了。

常见问题
问题一 不允许修改 partition_balance_schedule_interval
报错如下。
mysql> ALTER SYSTEM SET partition_balance_schedule_interval = '20s';
ERROR 4179 (HY000): DBMS_SCHEDULER job 'SCHEDULED_TRIGGER_PARTITION_BALANCE' is enabled. Operation is not allowed
报错分析。
OceanBase 数据库 V4.2.1 BP9 和 OceanBase 数据库 V4.2.4 起,partition_balance_schedule_interval 默认值从 2h 变为 0, 不再建议通过配置项 partition_balance_schedule_interval 来控制分区均衡,定时分区均衡任务SCHEDULED_TRIGGER_PARTITION_BALANCE 默认开启,参考手动触发负载均衡方法二。
可能通过如下 SQL 查询定时分区均衡任务。
SELECT job_name,job_style,job_type,job_action,start_date,repeat_interval,next_run_date,comments FROM dba_scheduler_jobs WHERE job_name = 'SCHEDULED_TRIGGER_PARTITION_BALANCE';
查询结果如下。
mysql> SELECT job_name,job_style,job_type,job_action,start_date,repeat_interval,next_run_date,comments FROM dba_scheduler_jobs WHERE job_name = 'SCHEDULED_TRIGGER_PARTITION_BALANCE'\G
*************************** 1. row ***************************
JOB_NAME: SCHEDULED_TRIGGER_PARTITION_BALANCE
JOB_STYLE: REGULER
JOB_TYPE: STORED_PROCEDURE
JOB_ACTION: DBMS_BALANCE.TRIGGER_PARTITION_BALANCE()
START_DATE: 2025-01-11 00:00:00.000000
REPEAT_INTERVAL: FREQ=DAILY; INTERVAL=1
NEXT_RUN_DATE: 2025-01-16 00:00:00.000000
COMMENTS: used to auto trigger partition balance
1 row in set (0.04 sec)
问题二 分区已均衡,不再需要进行负载均衡
报错如下。
MySQL [oceanbase]> CALL dbms_balance.trigger_partition_balance();
ERROR 7124 (HY000): partitions are already balanced, no need to trigger partition balance
报错分析:分区已均衡,不再需要进行负载均衡。
影响租户
影响 OceanBase 数据库中的 Oracle 租户和 MySQL 租户,对于 SYS 租户无影响。
适用版本
OceanBase 数据库 V4.x 版本。