---
title: "合并问题排查 | OceanBase 文档中心"
description: 合并问题排查 本文主要介绍合并慢、超时问题的排查方法。 适用版本 OceanBase 数据库所有版本 问题排查思路 在进行合并问题排查时，首先要确定当前集群中的合并配置项，确定当前的合并状态，然后根据查询得到的情况，对不同的合并问题类型进行分析后再寻找根因。 确认合并配置项 OceanBase 数据库中包含以下合并相…
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*P8CuR4UJ_FkAAAAAAAAAAAAADiGDAQ/original) OceanBase 数据库分布式版 - V 3.2.4 企业版 LTS

# 合并问题排查

更新时间：2026-06-19 09:35:18

本文主要介绍合并慢、超时问题的排查方法。

## 适用版本

OceanBase 数据库所有版本

## 问题排查思路

在进行合并问题排查时，首先要确定当前集群中的合并配置项，确定当前的合并状态，然后根据查询得到的情况，对不同的合并问题类型进行分析后再寻找根因。

### 确认合并配置项

OceanBase 数据库中包含以下合并相关的配置项：

- `enable_manual_merge`：是否开启手动合并，取值为 `TRUE` 表示需要手动合并，默认为 `FALSE`。
 - `zone_merge_concurrency`：用于设置在合并时，支持多少个 Zone 并发。当值为 `0` 时，由系统根据部署情况自动选择最佳并发度，一般不需要设置。默认为 `1`，表示单次只有一个 Zone 进行合并。
 - `zone_merge_order`：用于设置 Zone 的轮转合并顺序。不指定时，由系统自动决定，一般不需要设置。
 - `enable_merge_by_turn`：用于设置是否开启轮转合并策略，设置为 `TRUE` 时表示开启轮转合并，默认为 `FALSE`。
 - `major_freeze_duty_time`：每日合并发起时间。
 - `enable_auto_leader_switch`：用于设置是否开启自动切主，默认为 `TRUE`。

有关以上系统配置项的详细信息，请参见《OceanBase 数据库 参考指南》中的 **配置项参考** 章节。

### 确认合并状态

本例中，当前的 `frozen_version` 为 `25`，表示集群需要合并到 `25` 版本，但 `cn-shanghai-e` 这个 Zone 副本只合并到了 `24` 版本。

```sql
obclient> SELECT * FROM __all_zone WHERE name = "frozen_version" or name = "last_merged_version";
+----------------------------+----------------------------+---------------+---------------------+-------+------+
| gmt_create                 | gmt_modified               | zone          | name                | value | info |
+----------------------------+----------------------------+---------------+---------------------+-------+------+
| 2020-12-07 16:01:30.793286 | 2020-12-30 02:00:00.445594 |               | frozen_version      |    25 |      |
| 2020-12-07 16:01:30.793490 | 2020-12-29 02:01:12.449651 |               | last_merged_version |    24 |      |
| 2020-12-07 16:01:30.794375 | 2020-12-29 02:01:11.880114 | cn-shanghai-e | last_merged_version |    24 |      |
| 2020-12-07 16:01:30.795109 | 2020-12-30 02:01:15.563291 | cn-shanghai-f | last_merged_version |    25 |      |
| 2020-12-07 16:01:30.795842 | 2020-12-30 02:01:22.694016 | cn-shanghai-g | last_merged_version |    25 |      |
+----------------------------+----------------------------+---------------+---------------------+-------+------+
5 rows in set (0.00 sec)

```

继续查询 `__all_zone` 表，查看 `cn-shanghai-e` 的合并状态，发现状态为 `MERGING`，表示正在合并。

```shell
obclient> SELECT * FROM __all_zone WHERE name = "merge_status";
+----------------------------+----------------------------+---------------+---------------------+---------+------+
| gmt_create                 | gmt_modified               | zone          | name                | value   | info |
+----------------------------+----------------------------+---------------+---------------------+---------+------+
| 2020-12-07 16:01:30.793286 | 2020-12-30 02:00:00.445594 |               | merge_status        | MERGING |      |
| 2020-12-07 16:01:30.794375 | 2020-12-29 02:01:11.880114 | cn-shanghai-e | merge_status        | MERGING |      |
| 2020-12-07 16:01:30.795109 | 2020-12-30 02:01:15.563291 | cn-shanghai-f | merge_status        |   IDLE  |      |
| 2020-12-07 16:01:30.795842 | 2020-12-30 02:01:22.694016 | cn-shanghai-g | merge_status        |   IDLE  |      |
+----------------------------+----------------------------+---------------+---------------------+---------+------+
5 rows in set (0.00 sec)

```

## 合并问题类型

根据上面查询到的信息，一般情况下可以分为以下几类：未合并问题、合并超时问题、合并慢问题。下面针对每一类问题进行详细的分析。

### 未合并问题

未合并问题分为两类：RootService 没有发起相关 Zone 的合并和副本未合并。

#### Zone 未合并

根据上面的信息，发现正在合并，此时查询该 Zone 的 `global_broadcast_version` 与 `broadcast_version`。 如果 `broadcast_version` 等于 `last_merged_version`，且 `last_merged_version` 落后于 `global_broadcast_version`，说明 RootService 没有发起相关 Zone 的合并 。

```shell
obclient> SELECT * FROM __all_zone WHERE name = "global_broadcast_version" or name = "broadcast_version";
+----------------------------+----------------------------+---------------+--------------------------+---------+------+
| gmt_create                 | gmt_modified               | zone          | name                     | value   | info |
+----------------------------+----------------------------+---------------+--------------------------+---------+------+
| 2020-12-07 16:01:30.793286 | 2020-12-30 02:00:00.445594 |               | global_broadcast_version |   25    |      |
| 2020-12-07 16:01:30.794375 | 2020-12-29 02:01:11.880114 | cn-shanghai-e | broadcast_version        |   24    |      |
| 2020-12-07 16:01:30.795109 | 2020-12-30 02:01:15.563291 | cn-shanghai-f | broadcast_version        |   25    |      |
| 2020-12-07 16:01:30.795842 | 2020-12-30 02:01:22.694016 | cn-shanghai-g | broadcast_version        |   25    |      |
+----------------------------+----------------------------+---------------+--------------------------+---------+------+
5 rows in set (0.00 sec)

```

对于 RootService 未发起相关 Zone 合并的情况，按以下方法排查：

1. 排查 RootService 合并调度线程是否有报错。

   如果有返回值，则说明合并调度线程存在错误。

   ```shell
   grep "daily.*merge.*ret=-" rootservice.log

   ```
 2. 检查集群是否正在补副本。 如果以下查询有返回值，则说明正在进行副本的负载均衡。

   ```shell
   obclient> SELECT count(*) FROM __all_virtual_replica_task;

   ```

#### 副本未合并

本例继续假设当前要合并的目标版本是 `25`，查询 meta 表查看 `data_version != 25` 的副本以缩小排查范围。

- 对于 OceanBase 数据库 V1.X 版本，查询 `__all_virtual_core_meta_table`、`__all_virtual_core_root_table`、`__all_root_table` 与 `__all_meta_table` 表。
 - 对于 OceanBase 数据库 V2.X 及后续版本，查询 `__all_virtual_core_meta_table`、`__all_virtual_core_root_table`、`__all_root_table` 与 `__all_virtual_meta_table` 表。

```shell
obclient> SELECT * FROM __all_virtual_meta_table WHERE data_version != 25 LIMIT 10;
+-----------+------------------+--------------+---------------+----------+----------------------------+----------------------------+----------+---------+---------------+---------------+------+-----------------------------------------------------------------------------------------------------------+-----------+-----------+--------------+---------------+--------------+-----------------+--------------------+--------------------+-------------+---------+--------------+---------------+-----------------------+------------+--------------------+--------+-----------+--------------------+------------------+
| tenant_id | table_id         | partition_id | svr_ip        | svr_port | gmt_create                 | gmt_modified               | sql_port | unit_id | partition_cnt | zone          | role | member_list                                                                                               | row_count | data_size | data_version | data_checksum | row_checksum | column_checksum | is_original_leader | is_previous_leader | create_time | rebuild | replica_type | required_size | status                | is_restore | partition_checksum | quorum | fail_list | recovery_timestamp | memstore_percent |
+-----------+------------------+--------------+---------------+----------+----------------------------+----------------------------+----------+---------+---------------+---------------+------+-----------------------------------------------------------------------------------------------------------+-----------+-----------+--------------+---------------+--------------+-----------------+--------------------+--------------------+-------------+---------+--------------+---------------+-----------------------+------------+--------------------+--------+-----------+--------------------+------------------+
|      1001 | 1100611139463766 |            0 | xxx.xxx.x.xa |     xxxx | 2020-12-29 10:34:15.176561 | 2020-12-29 10:34:15.205753 |     2881 |    1001 |             0 | cn-shanghai-e |    1 | xxx.xxx.x.xx:2882:1609209255175464,xxx.xxx.x.xx:2882:1609209255175464,xxx.xxx.x.xx:2882:1609209255175464 |         0 |         0 |           24 |             0 |            0 |                 |                  0 |   1609209255204831 |           0 |       0 |            0 |             0 | REPLICA_STATUS_NORMAL |          0 |                  0 |      3 |           |                  0 |              100 |
+-----------+------------------+--------------+---------------+----------+----------------------------+----------------------------+----------+---------+---------------+---------------+------+-----------------------------------------------------------------------------------------------------------+-----------+-----------+--------------+---------------+--------------+-----------------+--------------------+--------------------+-------------+---------+--------------+---------------+-----------------------+------------+--------------------+--------+-----------+--------------------+------------------+
1 row in set (0.07 sec)

```

根据上面的信息，发现是 pkey 为`{tid:1100611139463766, partition_id:0}` 的表在 `xxx.xxx.x.xa:xxxx` 机器上未合并。

也可以通过搜索 `rootservice.log` 定位是哪个表阻塞了合并。

### 合并超时问题

1. 定位未合并到指定版本的 partition。

      1. 进数据库查询

        例如当前要合并的目标版本是 25，可以去 meta 表看 `data_version != 25` 的副本，从而缩小排查范围。

        > **说明**
        >
        >  
        >
        > 这里 meta 表指一组表，一般先看最后一级 meta 表 `__all_meta_table`/`__all_virtual_meta_table`）有没有 data_version 没推上去的副本，没有的话，查看更上一级的 meta 表。 对于 V2.0 以下版本，meta 表指：`__all_virtual_core_meta_table`、`__all_virtual_core_root_table`、`__all_root_table`、`__all_meta_table`。 对于 V2.0 及以上版本，meta 表指`__all_virtual_core_meta_table`、`__all_virtual_core_root_table`、`__all_root_table`、`__all_virtual_meta_table`。
      2. 在数据库后台查询。

        以 `not merged` 为关键词搜索 RS 所在机器上的最新的 `rootservice.log`。
 2. 判断该 partition 的合并任务是否在执行中。

   ```shell
   SELECT * FROM __all_virtual_sys_task_status;

   ```

   可以通过该虚拟表拿到执行的 trace，然后去对应机器上查询，判断合并任务是否卡住。
 3. 如果该 partition 没有调度合并任务，判断该 partition 的最新的转储 SSTable 的 `frozen_version` 有没有推过 `freeze_info` 点，如果没有推过 `freeze_info` 点，说明转储有问题。

   ```shell
   SELECT * FROM __all_virtual_table_mgr WHERE table_id = xxx and partition_id = xxx;

   SELECT * FROM __all_virtual_freeze_info;

   ```

   如果没有获取任何有用信息，可以搜索最近一段时间的 `observer.log` 的 ERROR 日志来获取线索。

### 合并慢问题

如果合并还未结束，可以按照合并超时的排查路径进行排查。如果合并已经完成，可以按照以下步骤进行排查。

1. 通过 SQL 查询指定 Major 版本的合并信息统计，找到合并耗时最多的几个 partition 来具体分析。

   ```shell
   SELECT /*+ query_timeout(10000000)*/* FROM __all_virtual_partition_compaction_history WHERE merge_type = "major merge" and merge_version = "<merge_version>" ORDER BY (merge_finish_time - merge_start_time) desc limit 5;

   ```

   #### 说明

   `version` 有三个字段，第一个非 0 字段是 `merge_version`，查询时需要替换成本次合并的 `merge_version`，后两个字段保持为 `0` 即可。

   您可通过 `__all_zone` 表可以查到本次合并的 `merge_version`。
 2. 通过表 `__all_virtual_partition_sstable_macro_info` 查看宏块重用情况。

   步骤 1 中的 `occupy_size` 、 `macro_block_count`、`use_old_macro_block_count` 、`rewrite_macro_old_micro_block_count` 、`rewrite_macro_total_micro_block_count` 等字段，分别表示该 partition 的数据量、宏块数、重用宏块数、重用宏块中重写的微块数。如果重用宏块数量 、总宏块数的比率非常低有可能会产生合并变慢的情况，这种情况有可能发生在新导入表的第一次合并或随机写严重，导致发生了全量合并。
 3. 查看合并开始时间是否合理。

   ```shell
   SELECT * FROM __all_virtual_partition_sstable_macro_info WHERE table_id = xxx and partition_id = xxx and svr_ip = "xxx" ORDER BY merge_finish_time desc LIMIT 10;

   ```

   找到合并开始最晚的几个 partition，在该时间段的 `observer.log` 中搜索其 compaction 记录。

   ```shell
   grep "sstable merge finish.* table_id.* partition_id" observer.log.20211117* | vi -

   ```

   如果有报错信息，

   a. V3.x 之前的版本，报错 `-4288(constexpr int OB_MEMTABLE_CANNOT_MINOR_MERGE = -4288;)`，表示 MemTable 上有未决事务导致转储失败，需要进一步对事务层面进行排查。

   b. 其他报错需要在合并模块进行排查。

从合并实现的原理来说，合并会将有修改的数据宏块打开重写（速度慢），没有修改的数据宏块直接重用（将老的数据宏块直接刷盘，速度快）全量合并，即所有的宏块都打开重写，所以有可能会造成速度慢的问题。

在 V3.2 及以后的版本上，提高了支持功能，您可以查询表`__all_virtual_compaction_suggestion` 来进一步诊断合并慢的原因。

## 问题排查步骤

1. 登录到未完成合并的 OBServer，查看是否存在磁盘 I/O 瓶颈。

   在 Shell 中执行 `iostat` 命令查看服务器的合并状态，如果使用率 100%，并且 `await` 值偏高，那么很有可能硬件出现了异常，需要检查硬件状况。

   ```shell
   [root@hostname /]# iostat -x 1 -k

   ```
 2. 如果通过 `iostat` 命令检查的 `await` 值偏低，但整体的 I/O 带宽不高，可以在 Shell 中执行以下命令查看是否存在限速。

   ```shell
   [admin@hostname log]$ grep "iostat" observer.log

   ```

   通过以上命令得到 OBServer 的 I/O 统计信息中，有 `sys_io_percent` 与 `sys_iops_up_limit` 两个字段。其中 `sys_io_percent` 表示当前系统 I/O 的使用百分比，`sys_iops_up_limit` 表示系统 2MB I/O 能力的上限。

      - 如果 `sys_iops_up_limit` 大于 `iostat` 的带宽使用量，则说明 I/O 余量充足，但 CPU 存在瓶颈，无法使用更多的带宽。
      - 如果 `sys_iops_up_limit` 小于 `iostat` 的带宽使用量，则说明 I/O 可能被限速了，需要调整最大允许使用的 I/O。OceanBase 数据库的 I/O 速度限制由 `sys_bkgd_io_low_percentage` 与 `sys_bkgd_io_high_percentage` 控制，分别表示 `sys_io_percent` 的下限与上限。如果下限过低，则可能导致合并过慢，可以适当调整这个配置项调大 I/O 限制。

       有关以上配置项的详细信息，请参见《OceanBase 数据库 参考指南》中的 **系统配置项** 章节。
      - 如果上述步骤中，发现性能瓶颈为 CPU，可以调整 `merge_thread_count` 配置项调整合并的线程数。

       `merge_thread_count` 用于设置每日合并工作的线程数，默认为 `0`，表示线程数由系统决定，取值范围为 `[0,64]`。

       有关该配置项的详细信息，请参见《OceanBase 数据库 参考指南》中的 **系统配置项** 章节。
 3. 经过以上排查步骤后，仍不能解决问题，则还有可能是以下场景中写入的数据量太大导致的合并时间过长：

      - 由于积攒了过多的转储，新增的数据过多，此时可以适当调小 `minor_freeze_times` 来更频繁的触发合并。

       `minor_freeze_times` 用于设置单个租户冻结多少次后触发一次全局合并，默认为 `5`，取值范围为 `[0,65535]`。设置为 `0` 时，表示只要冻结就会自动触发一次合并。

       有关该配置项的详细信息，请参见《OceanBase 数据库 参考指南》中的 **系统配置项** 章节。
      - 写入放大过大，由于合并的时候需要将基线和转储的数据合起来，如果基线的宏块和增量数据有交集，就需要打开重写；如果增量数据的写入非常离散那么就会导致写入放大很多。这种情况可以适当调大 `merge_thread_count` 来缓解。

       #### 注意

       业务上应尽量避免放大过大，主键尽量不要使用写入会非常随机的字段。例如，在使用 OceanBase 数据库时需要避免使用 UUID 做主键。/p>

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
