---
title: 子查询改写错误导致 SQL 查询结果为空的问题-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于 子查询改写错误导致 SQL 查询结果为空的问题相关的常见问题和使用技巧，帮助您快速解决 子查询改写错误导致 SQL 查询结果为空的问题的难题。
---
切换语言

- 简体中文
- English

划线反馈

# 子查询改写错误导致 SQL 查询结果为空的问题

更新时间：2026-05-15 09:06

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

## 问题现象

存在问题的 OceanBase 数据库版本中，原始 SQL 是一个子查询语句，原始 SQL 计划算子只有一个 0 号算子 TABLE SCAN，WHERE 条件中谓词 IN 和 NOT 条件都没有扫描，查询结果为空，不符合预期。

![1](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/knowledge-base/database/sql/20250331Subquery%20rewriting%20bug%20causes%20query%20result01.png)

最小化用例复现。

1. 创建表。

   ```shell
   obclient [SYS]> CREATE TABLE t11 (c1 NUMBER(10),c2 NUMBER(10));
   Query OK, 0 rows affected (0.030 sec)

   ```

   ```shell
   obclient [SYS]> CREATE TABLE t22 (x1 NUMBER(10) PRIMARY KEY);
   Query OK, 0 rows affected (0.058 sec)

   ```
 2. 插入数据。

   ```shell
   obclient [SYS]> INSERT INTO t11 VALUES (1,2);
   Query OK, 1 row affected (0.011 sec)

   ```

   ```shell
   obclient [SYS]> INSERT INTO t22 VALUES (1);
   Query OK, 1 row affected (0.004 sec)

   ```
 3. 执行未添加 Hint 提示 `/*+ NO_REWRITE */` 的子查询语句。

   ```shell
   obclient [SYS]> SELECT x1 FROM t22 WHERE x1 IN (SELECT a.c1 FROM t11 a) AND x1 NOT IN (SELECT a.c2 FROM t11 a);

   ```

   输出结果如下：

   ```shell
   Empty set (0.002 sec)

   ```

   子查询语句的执行计划：

   ```shell
   obclient [SYS]> explain SELECT  x1 FROM t22 WHERE x1 IN (SELECT a.c1 FROM t11 a) AND x1 NOT IN (SELECT a.c2 FROM t11 a);

   ```

   输出结果如下:

   ```shell
   +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
   | Query Plan                                                                                                                                                                                                                                                                                                                                        |
   +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
   | ===================================
   |ID|OPERATOR  |NAME|EST. ROWS|COST|
   -----------------------------------
   |0 |TABLE SCAN|T22 |1        |46  |
   ===================================

   Outputs & filters:
   -------------------------------------
   0 - output([T22.X1]), filter(nil), startup_filter([0]),
      access([T22.X1]), partitions(p0)
   |
   +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
   1 row in set (0.002 sec)

   ```
 4. 执行添加 Hint 提示 `/*+ NO_REWRITE */` 的子查询语句。

   下面为添加 Hint 提示 `/*+ NO_REWRITE */` 计划输出结果符合预期。

   ![2](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/knowledge-base/database/sql/20250331Subquery%20rewriting%20bug%20causes%20query%20result02.png)

   ```shell
   obclient [SYS]> SELECT /*+ NO_REWRITE */ x1 FROM t22 WHERE x1 IN (SELECT a.c1 FROM t11 a) AND x1 NOT IN (SELECT a.c2 FROM t11 a);

   ```

   输出结果如下：

   ```shell
   +----+
   | X1 |
   +----+
   |  1 |
   +----+
   1 row in set (0.003 sec)

   ```

   ```shell
   obclient [SYS]> explain SELECT /*+ NO_REWRITE */ x1 FROM t22 WHERE x1 IN (SELECT a.c1 FROM t11 a) AND x1 NOT IN (SELECT a.c2 FROM t11 a);

   ```

   输出结果如下：

   ```shell
   +------------------------------------------------------------------------------------------------------+
   | Query Plan                                                                                           |
   +------------------------------------------------------------------------------------------------------+
   | =================================================                                                    |
   | |ID|OPERATOR         |NAME|EST.ROWS|EST.TIME(us)|                                                    |
   | -------------------------------------------------                                                    |
   | |0 |SUBPLAN FILTER   |    |1       |12          |                                                    |
   | |1 |├─TABLE FULL SCAN|T22 |1       |4           |                                                    |
   | |2 |├─TABLE FULL SCAN|A   |1       |4           |                                                    |
   | |3 |└─TABLE FULL SCAN|A   |1       |4           |                                                    |
   | =================================================                                                    |
   | Outputs & filters:                                                                                   |
   | -------------------------------------                                                                |
   |   0 - output([T22.X1]), filter([T22.X1 = ANY(subquery(1))], [T22.X1 != ALL(subquery(2))]), rowset=16 |
   |       exec_params_(nil), onetime_exprs_(nil), init_plan_idxs_([1], [2]), use_batch=false             |
   |   1 - output([T22.X1]), filter(nil), rowset=16                                                       |
   |       access([T22.X1]), partitions(p0)                                                               |
   |       is_index_back=false, is_global_index=false,                                                    |
   |       range_key([T22.X1]), range(MIN ; MAX)always true                                               |
   |   2 - output([A.C1]), filter(nil), rowset=16                                                         |
   |       access([A.C1]), partitions(p0)                                                                 |
   |       is_index_back=false, is_global_index=false,                                                    |
   |       range_key([A.__pk_increment]), range(MIN ; MAX)always true                                     |
   |   3 - output([A.C2]), filter(nil), rowset=16                                                         |
   |       access([A.C2]), partitions(p0)                                                                 |
   |       is_index_back=false, is_global_index=false,                                                    |
   |       range_key([A.__pk_increment]), range(MIN ; MAX)always true                                     |
   +------------------------------------------------------------------------------------------------------+

   ```

## 关键诊断信息

### 事前巡检

命中这个 BUG 的 SQL 是一个包含两个子查询的 SQL，子查询会出现在 WHERE 条件中谓词 IN 和 NOT IN 的后面，并且子查询查询的表是同一张表的不同列（子查询查询是同一张表 t11 的不同列 c1 和 c2 列）下面是示例 SQL。

```shell
SELECT  x1 FROM t22 WHERE x1 IN (SELECT a.c1 FROM t11 a) AND x1 NOT IN (SELECT a.c2 FROM t11 a);

```

### 事后诊断

存在问题的 SQL 包含两个子查询，子查询中查询的表是同一张表的不同列，并且计划中只有一个 0 号算子 TABLE SCAN，执行结果为无数据不符合预期，通过加 Hint `/*+ NO_REWRITE */` 可以得到预期正确结果，可以判断为此问题。

![79jyi-yi7802-hi789-huyo96y](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/knowledge-base/database/sql/20231219SQL001.png)

## 问题原因

子查询合并时，没有校验两个 subquery 的投影项是否一致，SQL 的两个 subquery 的投影项是不同的，但是却做了子查询合并改写，误认为投影项是相同的，当做恒假的语句做了子查询合并改写导致结果为空。

```

**说明谓词 IN 和 NOT IN 后面是子查询，子查询表 t11 是相同表的不同列 c1 和 c2 列，如果列名相同则可以合并如下面 SQL**。

```shell
SELECT  x1 FROM t22 WHERE x1 IN (SELECT a.c1 FROM t11 a) AND x1 NOT IN (SELECT a.c1 FROM t11 a);

```

## 问题的风险及影响

存在问题的 OceanBase 数据库执行 SQL 如果命中子查询合并 BUG 会导致正确性问题。

#### 注意

该问题在 Oracle 租户 和 MySQL 租户下均存在。

## 影响租户

影响 OceanBase 数据库中的 SYS 租户和 Oracle 租户以及 MySQL 租户。

## 影响的版本

OceanBase 数据库企业版 V2.2.77 BP18（oceanbase-2.2.77-118000012023052520）之后版本、V3.1.2 BP11 (oceanbase-3.1.2-111000052023010412) 及之后版本、V3.2.3 BP10 Hotfix3 (oceanbase-3.2.3.3-110030012023101913) 及之后版本、V4.1.0 BP2 (oceanbase-4.1.0.1-102000042023061309) 及之后版本。

## 解决方法

升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V2.2.77 BP19（oceanbase-2.2.77-119000122024060513）、V3.2.3 BP10 Hotfix4（oceanbase-3.2.3.3-110040022023110614）、V3.2.3 BP10 Hotfix5（oceanbase-3.2.3.3-110050012023112210）、V3.2.3 BP10 Hotfix6（oceanbase-3.2.3.3-110060012024011615）、V3.2.3 BP10 Hotfix7（oceanbase-3.2.3.3-110070012024012316）、V3.2.3 BP10 Hotfix8（oceanbase-3.2.3.3-110080012024022713）、V3.2.3 BP10 Hotfix9（oceanbase-3.2.3.3-110090012024041611）、V3.2.3 BP10 Hotfix10（oceanbase-3.2.3.3-110100012024042814）、V3.2.3 BP10 Hotfix11（oceanbase-3.2.3.3-110110032024052217）、V3.2.3 BP10 Hotfix12（oceanbase-3.2.3.3-110120012024060510）、V3.2.3 BP10 Hotfix13（oceanbase-3.2.3.3-110130012024061819）、V3.2.3 BP10 Hotfix14（oceanbase-3.2.3.3-110140012024082010）、V3.2.3 BP10 Hotfix15（oceanbase-3.2.3.3-110150012024102111）、V3.2.3 BP10 Hotfix16（oceanbase-3.2.3.3-110160012025021315）、V3.2.3 BP10 Hotfix17（oceanbase-3.2.3.3-110170012025032112）、V3.2.3 BP10 Hotfix18（oceanbase-3.2.3.3-110180012025060316）、V3.2.3 BP10 Hotfix19（oceanbase-3.2.3.3-110190022025082615）、V3.2.3 BP10 Hotfix20（oceanbase-3.2.3.3-110200012025111317）、V3.2.3 BP11（oceanbase-3.2.3.3-111000032024070822）、V4.1.0 BP3（oceanbase-4.1.0.2-103000072023081111）。

## 规避方式

使用 Hint 提示 `/*+ NO_REWRITE */` 禁止改写。

Previous

[优化器将 exists 改写成 semi-join 后变慢的原因？](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000477585)

Next

[优化器将 NOT EXISTS 改写成 Anti-Join 后变慢的原因？](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000475695) ![有帮助](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) 咨询热线
