---
title: null 查询结果不正确-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于null 查询结果不正确相关的常见问题和使用技巧，帮助您快速解决null 查询结果不正确的难题。
---
切换语言

- 简体中文
- English

划线反馈

# null 查询结果不正确

更新时间：2026-05-26 09:46

适用版本： V2.2.x 内容类型：Troubleshoot  

## 问题现象

查询预期返回 500 行左右数据，但是在 OceanBase 数据库上返回了 30 万行数据，禁用索引之后，查询结果恢复正常。

出现问题的表和对应索引结构如下：

```sql
CREATE TABLE "TBL_GRP_TSK_INFO" (
  "MODNO" VARCHAR2(15) NOT NULL,
  "TASKID" VARCHAR2(32),
  "BQTYPE" VARCHAR2(4),
  ......
  "PAY_STAT" VARCHAR2(1),
  ......
  CONSTRAINT "PK_TBL_GRP_TSK_INFO" PRIMARY KEY ("MODNO")
) COMPRESS FOR ARCHIVE REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0;

CREATE INDEX "GPS"."IDX_TBL_GRP_TSK_INFO_06" on "GPS"."TBL_GRP_TSK_INFO" (
 "BQTYPE",
 "PAY_STAT"
) GLOBAL ;

```

出现问题的 SQL：

```sql
select count(*) from (select
  modno
from
  tbl_grp_tsk_info t
where
  (
    t.bqtype = 'PLZR' or (
      t.isapp = '1' and t.bqtype = 'BQZR'
    )
  ) and tasksta = '99' and pay_stat != 'S' and pay_stat != 'F' and isnewobj = '0' and trim(isQFB) is null and pay_stat != 'U' )

```

SQL 对应执行计划：

```sql

====================================================================
|ID|OPERATOR            |NAME                      |EST. ROWS|COST |
--------------------------------------------------------------------
|0 |EXCHANGE IN REMOTE  |                          |1        |12347|
|1 | EXCHANGE OUT REMOTE|                          |1        |12347|
|2 |  TABLE SCAN        |T(IDX_TBL_GRP_TSK_INFO_06)|1        |12347|
====================================================================

Outputs & filters:
-------------------------------------
  0 - output([T.MODNO(0x7ee6fab04170)]), filter(nil)
  1 - output([T.MODNO(0x7ee6fab04170)]), filter(nil)
  2 - output([T.MODNO(0x7ee6fab04170)]), filter([T.ISNEWOBJ(0x7ee6fab01030) = '0'(0x7ee6fab00910)], [T.BQTYPE(0x7ee6faafb450) = 'PLZR'(0x7ee6faaf8c50) OR T.ISAPP(0x7ee6faafb740) = '1'(0x7ee6faaf9fb0) AND T.BQTYPE(0x7ee6faafb450) = 'BQZR'(0x7ee6faafac30)(0x7ee6faaf9330)(0x7ee6faaf7fd0)], [T.TASKSTA(0x7ee6faafe0b0) = '99'(0x7ee6faafd990)], [(T_OP_IS, trim(T.ISQFB(0x7ee6fab02c00))(0x7ee6fab01440), NULL, 0)(0x7ee6fab02210)]),
      access([T.BQTYPE(0x7ee6faafb450)], [T.ISAPP(0x7ee6faafb740)], [T.TASKSTA(0x7ee6faafe0b0)], [T.ISNEWOBJ(0x7ee6fab01030)], [T.ISQFB(0x7ee6fab02c00)], [T.MODNO(0x7ee6fab04170)]), partitions(p0),
      is_index_back=true, filter_before_indexback[false,false,false,false],
      range_key([T.BQTYPE(0x7ee6faafb450)], [T.PAY_STAT(0x7ee6faaff180)], [T.MODNO(0x7ee6fab04170)]), range(PLZR,MIN,MIN ; PLZR,F,MIN), (PLZR,F,MAX ; PLZR,S,MIN), (PLZR,S,MAX ; PLZR,U,MIN), (PLZR,U,MAX ; PLZR,NULL,MIN), (BQZR,MIN,MIN ; BQZR,F,MIN), (BQZR,F,MAX ; BQZR,S,MIN), (BQZR,S,MAX ; BQZR,U,MIN), (BQZR,U,MAX ; BQZR,NULL,MIN),
      range_cond([T.PAY_STAT(0x7ee6faaff180) != 'S'(0x7ee6faafea60)], [T.PAY_STAT(0x7ee6faaff180) != 'F'(0x7ee6faaffb30)], [T.PAY_STAT(0x7ee6faaff180) != 'U'(0x7ee6fab03630)])

Used Hint:
-------------------------------------
  /*+
      NO_REWRITE
  */

Outline Data:
-------------------------------------
  /*+
      BEGIN_OUTLINE_DATA
      INDEX(@"SEL$1" "GPS.T"@"SEL$1" "IDX_TBL_GRP_TSK_INFO_06")
      NO_REWRITE
      END_OUTLINE_DATA
  */

Plan Type:
-------------------------------------
REMOTE

Optimization Info:
-------------------------------------

T:table_rows:3696815, physical_range_rows:2048, logical_range_rows:1709, index_back_rows:1709, output_rows:0, est_method:local_storage, optimization_method=cost_based, avaiable_index_name[IDX_TBL_GRP_TSK_INFO_06,IDX_TBL_GRP_TSK_INFO_01,TBL_GRP_TSK_INFO], pruned_index_name[IDX_TBL_GRP_TSK_INFO_08,IDX_TBL_GRP_TSK_INFO_04,IDX_TBL_GRP_TSK_INFO_07,IDX_TBL_GRP_TSK_INFO_05,IDX_TBL_GRP_TSK_INFO_10,IDX_TBL_GRP_TSK_INFO_11,IDX_TBL_GRP_TSK_INFO_02,IDX_TBL_GRP_TSK_INFO_03], estimation info[table_id:1105009185973522, (table_type:1, version:0-1682532010457701-1682532010457701, logical_rc:1601, physical_rc:1601), (table_type:0, version:1682532000646043-1682532000646043-9223372036854775807, logical_rc:108, physical_rc:447)]
Parameters
-------------------------------------

```

## 问题原因

OceanBase 数据库是 LSM-Tree 架构数据库，每个数据表的分区内部都包含多个 SSTable，每个 SSTable 内部划分为多个 2M 的宏块，而宏块内部又存在多个变长的微块，这个结构可以近似理解为一个树状结构，为了在 SSTable 内部快速定位扫描数据，每个宏块和微块都维护了内部最大的主键值作为这个宏块或者微块的 EndKey。当用户有查询触发时，会先在宏块中二分定位到需要的宏块，然后再继续在这个宏块内对所有微块二分定位到需要的微块。

这个流程需要大量的主键比较，所以之前 OceanBase 数据库引入了一些优化手段，其中就包含了这次引出问题的一个优化，具体来说就是在存储层固化所有主键的比较函数，这个优化的初衷是为了在主键的比较过程中加速比较函数的查找，但是遗漏了索引表主键可能存在 null 并且扫描范围可能包含 null 的场景，在 Oracle 模式如果遇到扫描范围出现 null, 直接就判定 null 是最大值，最后导致扫描结果范围扩大。

综上看，这个问题出现需要前置条件：

- 索引扫描，并且索引键可能包含 null。
 - 索引需要有一定量宏块和微块数目，并且有多个宏块和微块的 EndKey 包含 null。
 - SQL 查询抽取出针对索引的 query range 要包含 null。

## 问题的风险及影响

根据上面描述提到的几个前置条件，索引的条件很多场景都会出现，但是索引上包含 null 的 query range 这个条件一般来说需要用户通过 `!=` 条件来让 SQL 走到索引，在大部分场景出现的概率较少。

该问题会影响数据查询的正确性。

## 影响的版本

OceanBase 数据库企业版 V2.2.x 版本

## 解决方法及规避方式

可通过如下方式进行规避：

- 禁用对应的索引
 - 尝试 hint 改变计划，避免抽取带 null 的 query range。

Previous

[查询 union 结果集和拆分单独执行 SQL 结果不符合预期](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000075120)

Next

[OceanBase 数据库 V3.2.4 版本开启向量化，通过函数索引过滤数据时结果错误](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000089872) ![有帮助](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) 咨询热线
