---
title: 排查 OceanBase 数据库 V4.x 环境中 MySQL 模式下，无主键表生成列做分区键时，表中存在 local unique index 时，存在潜在 core 问题-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于排查 OceanBase 数据库 V4.x 环境中 MySQL 模式下，无主键表生成列做分区键时，表中存在 local unique index 时，存在潜在 core 问题相关的常见问题和使用技巧，帮助您快速解决排查 OceanBase 数据库 V4.x 环境中 MySQL 模式下，无主键表生成列做分区键时，表中存在 local unique index 时，存在潜在 core 问题的难题。
---
切换语言

- 简体中文
- English

划线反馈

# 排查 OceanBase 数据库 V4.x 环境中 MySQL 模式下，无主键表生成列做分区键时，表中存在 local unique index 时，存在潜在 core 问题

更新时间：2026-05-21 01:56

适用版本： V4.1.x、V4.2.x、V4.3.x 内容类型：Troubleshoot  

## 问题现象

OceanBase 数据库 V4.x 环境中 MySQL 模式下，无主键表生成列做分区键时，表中存在 `local unique index` 时，存在潜在 core 问题。

复现 core 问题，示例。

1. 创建无主键，以生成列作为分区键的 hash 分区表 t5。

   ```shell
   obclient [mysql]> create table t5(c1 int, c2 int, c3 int as (c1 + c2) virtual) partition by hash(c3) partitions 4;
   Query OK, 0 rows affected (0.322 sec)

   ```
 2. 创建唯一索引 t5_idx_01，并且显式包含了分区键生成列 c3。

   ```shell
   obclient [mysql]> create unique index t5_idx_01 on t5(c1,c3) local;
   Query OK, 0 rows affected (0.627 sec)

   ```
 3. 创建唯一索引 t5_idx_02，由于唯一索引必须包含分区键，c1 和 c2是 分区键生成列 c3 列的依赖列，唯一索引创建成功。

   ```shell
   obclient [mysql]> create unique index t5_idx_02 on t5(c1,c2) local;
   Query OK, 0 rows affected (0.438 sec)

   ```
 4. 执行 replace 操作，成功。

   ```shell
   obclient [mysql]> replace into t5(c1, c2) values(1,1);
   Query OK, 1 row affected (0.054 sec)

   ```
 5. 执行 replace 操作，失败，core。

   ```shell
   obclient [mysql]> replace into t5(c1, c2) values(1,1);
   ERROR 2013 (HY000): Lost connection to MySQL server during query

   ```

## 关键诊断信息

### 触发条件

OceanBase 数据库 V4.x 环境，MySQL 模式，无主键表生成列做分区键，表中存在 `local unique index`。

### 事前巡检

对已有的 OceanBase 数据库 V4.x 环境中的 MySQL 租户中的表进行扫描，得到存在潜在风险的表，并且修改此表中可能会出现问题的索引。

### 事后诊断

已有环境潜在问题的排查步骤。

1. 步骤一。

   OceanBase 数据库 V4.x 环境下，在 SYS 租户中，确认当前的 MySQL 兼容模式下的用户租户中，是否存在分区键为生成列的无主键表，且在此表上存在没有包含分区键的 `local unique index`。在系统租户下，查询语句如下。

   ```shell
   obclient > WITH tmp_vc1 AS (
   select vc1.tenant_id as tenant_id, vc1.table_id as table_id, vc1.column_name as column_name from oceanbase.__all_virtual_column vc1 INNER JOIN
   (select tenant_id, table_id from (
   select vc.tenant_id as tenant_id, vc.table_id as table_id, vc.column_name as column_name from oceanbase.__all_virtual_column vc INNER JOIN (select table_id from oceanbase.__all_virtual_table where table_type = 3 and part_level
   in (1,2) and table_name not like '%__recycle_$%' and tenant_id in (select tenant_id from oceanbase.__all_tenant where
   compatibility_mode = 0 and tenant_name != 'sys' and tenant_name not like '%META$%')) AS sub1 on vc.table_id = sub1.table_id) group by table_id
   HAVING SUM(CASE WHEN column_name = '__pk_increment' THEN 1 ELSE 0 END) > 0) ERR_T
   on vc1.tenant_id = ERR_T.tenant_id and vc1.table_id = ERR_T.table_id and (vc1.column_flags & 1 = 1 or vc1.column_flags & 2 = 1)),
   final_data_table as (
   select VT_P_I.tenant_id, VT_P_I.table_id, VT_P_I.part_expr from oceanbase.__all_virtual_part_info VT_P_I INNER JOIN tmp_vc1 on VT_P_I.tenant_id = tmp_vc1.tenant_id and VT_P_I.table_id = tmp_vc1.table_id and find_in_set(VT_P_I.part_expr, tmp_vc1.column_name)),
   index_table as (
   select VT.tenant_id, VT.table_id from oceanbase.__all_virtual_table VT inner join final_data_table fdt on VT.tenant_id = fdt.tenant_id and VT.data_table_id = fdt.table_id and VT.index_type=2),
   new_column_set as (select distinct NEW_VCT.tenant_id as tenant_id, NEW_VCT.table_id as table_id from (
   select new_vc.tenant_id, new_vc.table_id, new_vc.column_name from oceanbase.__all_virtual_column new_vc inner join index_table idt on new_vc.tenant_id = idt.tenant_id and new_vc.table_id = idt.table_id) NEW_VCT inner join tmp_vc1 on NEW_VCT.tenant_id = tmp_vc1.tenant_id
   group by table_id HAVING sum(case when NEW_VCT.column_name = tmp_vc1.column_name then 1 else 0 end) = 0),
   target_index_table as (select distinct final_all_t.tenant_id, final_all_t.table_id, final_all_t.table_name, final_all_t.data_table_id from oceanbase.__all_virtual_table final_all_t inner join new_column_set on final_all_t.tenant_id = new_column_set.tenant_id and final_all_t.table_id = new_column_set.table_id order by table_id)
   select distinct ft.tenant_id, ft.table_id, ft.table_name from oceanbase.__all_virtual_table ft inner join target_index_table on ft.tenant_id = target_index_table.tenant_id and ft.table_id = target_index_table.data_table_id order by table_id;

   ```

   通过以上的查询语句就可以看到当前集群中的 MySQL 租户中，是否存在分区键为生成列的无主键表，且在此表上存在没有包含分区键的 `local unique index`。查询结果如下，说明表 t5、t6、t7 中存在符合条件的索引，需要进行调整。

   输出结果如下：

   ```shell
   +-----------+----------+------------+
   | tenant_id | table_id | table_name |
   +-----------+----------+------------+
   |      1004 |   500005 | t5         |
   |      1004 |   500020 | t6         |
   |      1004 |   500035 | t7         |
   +-----------+----------+------------+
   3 rows in set (3.295 sec)

   ```
 2. 步骤二。

   如果需要详细查看具体是哪些索引符合以上条件，可以在系统租户下执行以下语句。

   ```shell
   WITH tmp_vc1 AS (
   select vc1.tenant_id as tenant_id, vc1.table_id as table_id, vc1.column_name as column_name from oceanbase.__all_virtual_column vc1 INNER JOIN
   (select tenant_id, table_id from (
   select vc.tenant_id as tenant_id, vc.table_id as table_id, vc.column_name as column_name from oceanbase.__all_virtual_column vc INNER JOIN (select table_id from oceanbase.__all_virtual_table where table_type = 3 and part_level
   in (1,2) and table_name not like '%__recycle_$%' and tenant_id in (select tenant_id from oceanbase.__all_tenant where
   compatibility_mode = 0 and tenant_name != 'sys' and tenant_name not like '%META$%')) AS sub1 on vc.table_id = sub1.table_id) group by table_id
   HAVING SUM(CASE WHEN column_name = '__pk_increment' THEN 1 ELSE 0 END) > 0) ERR_T
   on vc1.tenant_id = ERR_T.tenant_id and vc1.table_id = ERR_T.table_id and (vc1.column_flags & 1 = 1 or vc1.column_flags & 2 = 1)),
   final_data_table as (
   select VT_P_I.tenant_id, VT_P_I.table_id, VT_P_I.part_expr from oceanbase.__all_virtual_part_info VT_P_I INNER JOIN tmp_vc1 on VT_P_I.tenant_id = tmp_vc1.tenant_id and VT_P_I.table_id = tmp_vc1.table_id and find_in_set(VT_P_I.part_expr, tmp_vc1.column_name)),
   index_table as (
   select VT.tenant_id, VT.table_id from oceanbase.__all_virtual_table VT inner join final_data_table fdt on VT.tenant_id = fdt.tenant_id and VT.data_table_id = fdt.table_id and VT.index_type=2),
   new_column_set as (select distinct NEW_VCT.tenant_id as tenant_id, NEW_VCT.table_id as table_id from (
   select new_vc.tenant_id, new_vc.table_id, new_vc.column_name from oceanbase.__all_virtual_column new_vc inner join index_table idt on new_vc.tenant_id = idt.tenant_id and new_vc.table_id = idt.table_id) NEW_VCT inner join tmp_vc1 on NEW_VCT.tenant_id = tmp_vc1.tenant_id
   group by table_id HAVING sum(case when NEW_VCT.column_name = tmp_vc1.column_name then 1 else 0 end) = 0)
   select distinct final_all_t.tenant_id, final_all_t.table_id, final_all_t.table_name, final_all_t.data_table_id from oceanbase.__all_virtual_table final_all_t inner join new_column_set on final_all_t.tenant_id = new_column_set.tenant_id and final_all_t.table_id = new_column_set.table_id order by table_id;

   ```

   结果如下所示，可以看到符合条件的索引以及其对应的主表 id。

   输出结果如下：

   ```shell
   +-----------+----------+------------------------+---------------+
   | tenant_id | table_id | table_name             | data_table_id |
   +-----------+----------+------------------------+---------------+
   |      1004 |   500019 | __idx_500005_t5_idx_02 |        500005 |
   |      1004 |   500034 | __idx_500020_t6_idx_02 |        500020 |
   |      1004 |   500049 | __idx_500035_t6_idx_02 |        500035 |
   +-----------+----------+------------------------+---------------+
   3 rows in set (3.133 sec)

   ```

## 问题原因

core 原因是 `replace into` 在 `try_insert` 时会将当前索引中冗余的主表主键返回回去，用于使得 `replace_into` 算子获知发生 unique 冲突的冲突行就需要使用主表的 隐藏自增列 + 分区键 来唯一的描述一行，但是上述的两个索引 t5_idx_01 和 t5_idx_02 分别冗余的主表 c3 列和 c1 + c2 列，t5_idx_02 索引中是没有冗余主表分区键 c3 列的，那么在写 t5_idx_02 时假设发生 unique 冲突，想要准确的描述出 当前发生 unique 冲突行对应主表的唯一键，就需要返回主表的隐藏自增列 + c1 + c2，但是 t5_idx_01 时假设发生 unique 冲突，只需要返回主表的隐藏自增列 + c3，那么从 DML 的层面上看，主表写一行数据，返回的多个冲突行的列数是完全不同的，t5_idx_02 返回 3 列，t5_idx_01 返回 2 列，数据无法统一处理，引起了 core。

## 问题的风险及影响

OceanBase 数据库 V4.x 环境下，如果主表存在文中所描述的局部唯一索引，在 `replace into` 操作时，可能会导致 OBServer core 掉。

## 影响租户

影响 OceanBase 数据库中的 MySQL 租户，对于 SYS 租户和 Oracle 租户无影响。

## 影响版本

OceanBase 数据库企业版 V4.1.0 GA（oceanbase-4.1.0.0-100001122023040322）及之后版本、V4.2.0 GA（oceanbase-4.2.0.0-100010082023083014）及之后版本、V4.2.1 GA（oceanbase-4.2.1.0-100000182023092722）及之后版本、V4.2.2 GA（oceanbase-4.2.2.0-100000082024011317）及之后版本、V4.3.0（oceanbase-4.3.0.0-100000072024020200）及之后版本。

## 解决方法及规避方式

- 解决方法：

     - **解决方法一**。

      升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V4.2.1 BP8（oceanbase-4.2.1.8-108000052024072217）及之后版本、V4.2.4（oceanbase-4.2.4.0-100000252024070621）及之后版本。
     - **解决方法二**。

      如果用户遇到此类问题，需要重新拉起 OBServer，并且使用本文档中**事后诊断**所描述的排查步骤去删除掉可能出现异常的局部唯一索引，并且重新构建包含分区键的唯一索引。

      在租户 MySQL 模式下针对存在以上条件的索引执行 `alter table drop` 操作删除掉相关索引，之后重新构建新的索引。

      #### 注意

      新的索引必须要包含分区键，例如分区键是 c3 列，那么索引中必须显式指定 c3 列。
 - 规避方式：

  利用本文档中描述的步骤去重新构建存在潜在风险的局部唯一索引。

Previous

[OceanBase 数据库 V3.2.4.x 无法创建临时表，报错 MySQL compatible temporary table not supported 的原因及解决方法](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000003651995)

Next

[因新引擎不支持 case column_namewhen 语法导致创建表时报错 -4016,this expr should be rewrote in new engine 的原因和解决方法](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000002022568) ![有帮助](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) 咨询热线
