---
title: SQL 查询中使用不等于谓词过多退化为全表扫描的原因和解决方法-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于 SQL 查询中使用不等于谓词过多退化为全表扫描的原因和解决方法相关的常见问题和使用技巧，帮助您快速解决 SQL 查询中使用不等于谓词过多退化为全表扫描的原因和解决方法的难题。
image: https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*OSPzQ6GUQF4AAAAAQHAAAAgAeiGDAQ/original
---
切换语言

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

划线反馈

# SQL 查询中使用不等于谓词过多退化为全表扫描的原因和解决方法

更新时间：2026-05-14 07:41

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

## 问题现象

在 OceanBase 数据库 V4.2.1 BP7 版本中，当执行包含多个 `<>`/`!=` 条件的 SQL 查询时，如果 `<>`/`!=` 条件的数量超过 12 个，即使存在合适的索引，查询也会退化为索引全表扫描，导致执行效率显著下降。 示例如下。

```shell
explain  extended_noaddr
select c1,c2,c3 from user_table
where c3 = 'a1dcdc796df77b19bf25a92c7ab00101' and (
c1 <>'0ac83825044e795455d3f01a353c71db' and
c1 <>'5bed7f5c49df9262feed4a8acfced477' and
c1 <>'daf9c12fa5f68b489b83905c1a96311b' and
c1 <>'0f5858b3b066c920483197d1bc586a10' and

c1 <>'b83bdf24874da0f9bba3dcde360f70b7' and
c1 <>'bfafdd1714093988575f93c9f52e3107' and
c1 <>'280cc2f28c2957042ad4aa2a7bd4f95e' and
c1 <>'f4da4437b7837df6abeb32c4931804da' and

c1 <>'70133539f5da84506227e4a6d478f8f4' and
c1 <>'9aaa73429257ebddcf760e6fc70a167e' and
c1 <>'de51330c941284c998dae0c259e5419d' and
c1 <>'79068315b1ce4458410a02114ff7ef3c'
);
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ================================================================================                                                                                                             |
| |ID|OPERATOR       |NAME                                 |EST.ROWS|EST.TIME(us)|                                                                                                             |
| --------------------------------------------------------------------------------                                                                                                             |
| |0 |TABLE FULL SCAN|user_table(idx_uni_change)|9       |52030864    |                                                                                                             |
| ================================================================================                                                                                                             |
| Outputs & filters:                                                                                                                                                                           |
| -------------------------------------                                                                                                                                                        |
|   0 - output([user_table.change_record], [user_table.company_name_digest], [user_table.use_flag]), filter([user_table.company_name_digest        |
|       = cast('a1dcdc796df77b19bf25a92c7ab00101', VARCHAR(1048576))], [user_table.change_record != cast('0ac83825044e795455d3f01a353c71db', VARCHAR(1048576))],                    |
|        [user_table.change_record != cast('5bed7f5c49df9262feed4a8acfced477', VARCHAR(1048576))], [user_table.change_record != cast('daf9c12fa5f68b489b83905c1a96311b', |
|        VARCHAR(1048576))], [user_table.change_record != cast('0f5858b3b066c920483197d1bc586a10', VARCHAR(1048576))], [user_table.change_record                         |
|       != cast('b83bdf24874da0f9bba3dcde360f70b7', VARCHAR(1048576))], [user_table.change_record != cast('bfafdd1714093988575f93c9f52e3107', VARCHAR(1048576))],                   |
|        [user_table.change_record != cast('280cc2f28c2957042ad4aa2a7bd4f95e', VARCHAR(1048576))], [user_table.change_record != cast('f4da4437b7837df6abeb32c4931804da', |
|        VARCHAR(1048576))], [user_table.change_record != cast('385c0ba617ae847d9587d8c578c78504', VARCHAR(1048576))], [user_table.change_record                         |
|       != cast('70133539f5da84506227e4a6d478f8f4', VARCHAR(1048576))], [user_table.change_record != cast('9aaa73429257ebddcf760e6fc70a167e', VARCHAR(1048576))],                   |
|        [user_table.change_record != cast('de51330c941284c998dae0c259e5419d', VARCHAR(1048576))], [user_table.change_record != cast('79068315b1ce4458410a02114ff7ef3c', |
|        VARCHAR(1048576))]), rowset=16                                                                                                                                                        |
|       access([user_table.id], [user_table.company_name_digest], [user_table.change_record], [user_table.use_flag]), partitions(p0)               |
|       is_index_back=true, is_global_index=false, filter_before_indexback[true,true,true,true,true,true,true,true,true,true,true,true,true,true],                                             |
|       range_key([user_table.company_name_digest], [user_table.change_record], [user_table.shadow_pk_0]), range(MIN,MIN,                                     |
|       MIN ; MAX,MAX,MAX)always true

```

## 关键信息

1. 通过 SQL 语句判断，如下示例。

   ```shell
    explain  extended_noaddr
    select c1,c2,c3 from user_table
    where c3 = 'xxx' and (c1 <>'xxx' and c1 <>'xxx' and c1 <>'xxx' and c1 <>'xxx' and
    c1 <>'xxx' and  c1 <>'xxx' and c1 <>'xxx' and  c1 <>'xxx' and
    c1 <>'xxx' and c1 <>'xxx' and c1 <>'xxx' and c1 <>'xxx' );

   ```

      - 当 `!=` 条件个数小于 12 个时，能够正常利用索引进行范围查询。
      - 当 `!=` 条件个数大于 12 个时，优化器无法有效利用索引，转为索引全表扫描。
      - 观察逻辑计划是否计划走索引但是抽取 `Query Range` 为 `range(MIN，MAX)`。  

   #### 注意

   `!=` 条件个数不是固定值，主要看抽取 `Query Range` 时耗费的内存，如果超限则可能抽取 Range 失败尝试走主表。
 2. 关键日志信息 `is_reach_mem_limit_=true,query_range_ctx_->range_optimizer_max_mem_size`。

   ```shell
    [2024-12-30 19:19:26.267494] WDIAG [SQL.REWRITE] deep_copy_key_part_and_items (ob_query_range.cpp:4771) [103267][T1004_L0_G0][T1004][xxxxx-xxxxx-xxxxx-xxxxx] [lt=14][errcode=0] use too much memory return always true keypart(mem_used_=696112, allocator_.used()=134914192)
    [2024-12-30 19:19:26.267524] WDIAG [SQL.REWRITE] and_range_graph (ob_query_range.cpp:5197) [103267][T1004_L0_G0][T1004][xxxxx-xxxxx-xxxxx-xxxxx] [lt=23][errcode=0] use too much memory(is_reach_mem_limit_=true, query_range_ctx_->range_optimizer_max_mem_size_=134217728)
    [2024-12-30 19:19:26.267531] WDIAG [SQL.REWRITE] and_range_graph (ob_query_range.cpp:5197) [103267][T1004_L0_G0][T1004][xxxxx-xxxxx-xxxxx-xxxxx] [lt=6][errcode=0] use too much memory(is_reach_mem_limit_=true, query_range_ctx_->range_optimizer_max_mem_size_=134217728)

   ```

## 问题原因

执行慢计划走索引但是抽不出来 `Query Range` 这个是内存的问题。具体来说例如 SQL 中存在 `c1 != xx` 会把 `c1!= xx` 展开为等效的 `c1 < xx or c1 > xx`，如果多个条件比如 13 个条件 `!=` 会展开为 `2^13` 个 `Query Range` 很暴力的展开内存的使用是 `2^13` 次方 ，这会导致内存消耗迅速增加，超过 `range_optimizer_mem_max_use` 参数设定的内存限制，从而使得优化器无法有效利用索引，转而采用全表扫描的方式执行查询。改字符集序能规避是字符集是因为不需要加 cast，内存占用少一点没超参数的内存限制索引能正常走索引抽出来 `Query Range`。

## 有关配置项 range_optimizer_mem_max_use

**默认值：** 128M。

**详细说明：** 在复杂谓词场景（常见的是 `IN` 表达式以及 `OR` 表达式很多的场景），优化器抽取 `Query Range` 时会耗费较大内存，甚至影响集群的正常使用。针对这一问题，MySQL 可通过 `range_optimizer_max_mem_size` 参数来限制抽取 `Query Range` 阶段所占用的内存。限制 `Query Range` 模块使用的内存使用。当 `Query Range` 模块使用的内存达到上限时，则不做任何 Range 的抽取。例如，某个复杂谓词命中了索引，如果对这个复杂谓词抽取 `Query Range` 时使用的内存达到了上限，那就不会选择这个索引，而是尝试走主表。

## 问题的风险及影响

如果计划走索引但是抽取 `Query Range` 为 `range(MIN，MAX)`，SQL 执行效率显著下降，可能导致查询响应时间延长。

## 适用版本

OceanBase 数据库 V4.2.x 版本。

## 解决方法

- 升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库 V4.2.5（oceanbase-4.2.5.0-100000082024102022）版本。
 - **调整 `range_optimizer_mem_max_use` 参数：** 如果不立即升级，可以通过增大 `range_optimizer_mem_max_use` 参数来临时缓解问题，但这仅能部分解决问题，因为内存使用量随 `!=` 条件数量的增加呈指数增长。

## 规避方式

- **修改SQL语句：** 将多个 `!=` 条件改为 `NOT IN`，这样可以避免优化器生成过多的范围查询，减少内存消耗（`NOT IN` 如果过多有报错的可能性 `-4013，No memory or reach tenant memory limit`）。
 - **字段的字符集序：** 通过保证字段的字符集序一致，可以避免 cast 转换减少内存占用，但这种方法只能轻微改善问题。

Previous

[large_query_worker_percentage 无法限制住 CPU](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000006084950)

Next

[如何排查常量约束导致的参数不匹配，计划不命中的问题](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000005438095) ![有帮助](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) 咨询热线
