---
title: 含 NLJ 计划结果可能不对问题-OceanBase数据库使用指南
description: 了解OceanBase数据库在实际应用中关于含 NLJ 计划结果可能不对问题相关的常见问题和使用技巧，帮助您快速解决含 NLJ 计划结果可能不对问题的难题。
---
切换语言

- 简体中文
- English

划线反馈

# 含 NLJ 计划结果可能不对问题

更新时间：2026-07-17 07:16

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

## 问题现象

示例，下面 query 预期执行结果为 40，实际执行出来为 26，结果不对；从 SQL Plan Monitor 中分析，可知 12 号算子吐行结果不对。

```shell
OceanBase(SYS@SYS)>explain SELECT /*+xtracing(1,12,13) no_use_px*/ Z.ACTINSTID FROM temp_tab Z WHERE 1=1   AND Z.ACTINSTID = (       SELECT /*+LEADING(A,E,F,H,B,D,C,G)*/DISTINCT ACTINSTID FROM V_JBPM4_TASKTRACKS M, (             SELECT /*+merge*/MAX(ACTGENDATE) AS CC, WFINSTID CC1 FROM temp_tab2 N group by WFINSTID)       WHERE (ACTACTOR = 'wangli-067')         AND WFCODE = Z.WFCODE AND WFINSTID = Z.WFINSTID         AND M.ACTGENDATE = CC AND CC1 = M.WFINSTID)\G
*************************** 1. row ***************************
Query Plan: ===========================================================================================
|ID|OPERATOR                            |NAME                            |EST. ROWS|COST  |
-------------------------------------------------------------------------------------------
|0 |SUBPLAN FILTER                      |                                |2        |138530|
|1 | TABLE SCAN                         |Z                               |166      |65    |
|2 | MERGE DISTINCT                     |                                |1        |835   |
|3 |  SORT                              |                                |1        |835   |
|4 |   MERGE GROUP BY                   |                                |1        |835   |
|5 |    SORT                            |                                |1        |835   |
|6 |     NESTED-LOOP JOIN CARTESIAN     |                                |1        |835   |
|7 |      TABLE SCAN                    |N                               |2        |54    |
|8 |      MATERIAL                      |                                |1        |781   |
|9 |       SUBPLAN SCAN                 |V_JBPM4_TASKTRACKS              |1        |781   |
|10|        MERGE DISTINCT              |                                |1        |781   |
|11|         SORT                       |                                |1        |781   |
|12|          NESTED-LOOP JOIN          |                                |1        |781   |
|13|           NESTED-LOOP OUTER JOIN   |                                |1        |761   |
|14|            NESTED-LOOP JOIN        |                                |1        |199   |
|15|             NESTED-LOOP JOIN       |                                |1        |174   |
|16|              NESTED-LOOP OUTER JOIN|                                |1        |147   |
|17|               NESTED-LOOP JOIN     |                                |1        |146   |
|18|                NESTED-LOOP JOIN    |                                |1        |119   |
|19|                 TABLE SCAN         |A(JBPM4_HIST_PROCINST_ID)       |1        |92    |
|20|                 TABLE SCAN         |E(JBPM4_DEPLOYPROP_STRINGVAL)   |1        |26    |
|21|                TABLE SCAN          |F(JBPM4_DEPLOYPROP_DEPLOYMENT)  |1        |26    |
|22|               TABLE SCAN           |H(IDX_JBPM4_TASK_PROCINST)      |60       |230   |
|23|              TABLE SCAN            |B(IDX_JBPM4_HIST_ACTINST_HPROCI)|2        |89    |
|24|             TABLE GET              |D                               |1        |29    |
|25|            TABLE SCAN              |C(IDX_JBPM4_PART_TASK)          |66       |750   |
|26|           TABLE SCAN               |G(JBPM4_DEPLOYPROP_DEPLOYMENT)  |1        |26    |
===========================================================================================

Outputs & filters:
-------------------------------------
  0 - output([Z.ACTINSTID]), filter([Z.ACTINSTID = subquery(1)]),
      exec_params_([Z.WFINSTID], [Z.WFCODE]), onetime_exprs_(nil), init_plan_idxs_(nil)
  1 - output([Z.WFCODE], [Z.WFINSTID], [Z.ACTINSTID]), filter(nil),
      access([Z.WFCODE], [Z.WFINSTID], [Z.ACTINSTID]), partitions(p0)
  2 - output([M.ACTINSTID]), filter(nil),
      distinct([M.ACTINSTID])
  3 - output([M.ACTINSTID]), filter(nil), sort_keys([M.ACTINSTID, ASC])
  4 - output([M.ACTINSTID]), filter([M.ACTGENDATE = T_FUN_MAX(N.ACTGENDATE)]),
      group([M.WFINSTSTATE], [M.ACTINSTID], [M.WFVER], [M.ACTCODE], [M.ACTCREDATE], [M.ACTENDDATE], [M.ACTGENDATE], [M.CURRACTCODE], [M.CURRACTINSTID], [M.INSTENDACTCODE]), agg_func([T_FUN_MAX(N.ACTGENDATE)])
  5 - output([M.ACTINSTID], [M.WFINSTSTATE], [M.WFVER], [M.ACTCODE], [M.ACTCREDATE], [M.ACTENDDATE], [M.ACTGENDATE], [M.CURRACTCODE], [M.CURRACTINSTID], [M.INSTENDACTCODE], [N.ACTGENDATE]), filter(nil), sort_keys([M.WFINSTSTATE, ASC], [M.ACTINSTID, ASC], [M.WFVER, ASC], [M.ACTCODE, ASC], [M.ACTCREDATE, ASC], [M.ACTENDDATE, ASC], [M.ACTGENDATE, ASC], [M.CURRACTCODE, ASC], [M.CURRACTINSTID, ASC], [M.INSTENDACTCODE, ASC])
  6 - output([M.ACTINSTID], [M.WFINSTSTATE], [M.WFVER], [M.ACTCODE], [M.ACTCREDATE], [M.ACTENDDATE], [M.ACTGENDATE], [M.CURRACTCODE], [M.CURRACTINSTID], [M.INSTENDACTCODE], [N.ACTGENDATE]), filter(nil),
      conds(nil), nl_params_(nil)
  7 - output([N.ACTGENDATE]), filter([? = N.WFINSTID]),
      access([N.WFINSTID], [N.ACTGENDATE]), partitions(p0)
  8 - output([M.ACTINSTID], [M.WFINSTSTATE], [M.WFVER], [M.ACTCODE], [M.ACTCREDATE], [M.ACTENDDATE], [M.ACTGENDATE], [M.CURRACTCODE], [M.CURRACTINSTID], [M.INSTENDACTCODE]), filter(nil)
  9 - output([M.ACTGENDATE], [M.ACTINSTID], [M.WFVER], [M.WFINSTSTATE], [M.ACTCODE], [M.ACTCREDATE], [M.ACTENDDATE], [M.CURRACTCODE], [M.CURRACTINSTID], [M.INSTENDACTCODE]), filter(nil),
      access([M.ACTACTOR], [M.WFCODE], [M.WFINSTID], [M.ACTGENDATE], [M.ACTINSTID], [M.WFVER], [M.WFINSTSTATE], [M.ACTCODE], [M.ACTSTATE], [M.ACTCREDATE], [M.ACTENDDATE], [M.CURRACTCODE], [M.CURRACTINSTID], [M.INSTENDACTCODE])
  10 - output([F.STRINGVAL_], [G.LONGVAL_], [A.ID_], [A.STATE_], [B.ACTIVITY_NAME_], [B.HTASK_], [D.STATE_], [B.START_], [B.END_], [B.DATE_], [H.NAME_], [H.DBID_], [CASE WHEN D.STATE_ = ? THEN D.ASSIGNEE_ ELSE CASE WHEN (T_OP_IS, C.USERID_, NULL, 0) THEN H.ASSIGNEE_ ELSE C.USERID_ END END], [A.ENDACTIVITY_]), filter(nil),
      distinct([A.STATE_], [B.HTASK_], [G.LONGVAL_], [B.ACTIVITY_NAME_], [B.START_], [B.END_], [B.DATE_], [H.NAME_], [H.DBID_], [A.ENDACTIVITY_])
  11 - output([F.STRINGVAL_], [G.LONGVAL_], [A.ID_], [A.STATE_], [B.ACTIVITY_NAME_], [B.HTASK_], [D.STATE_], [B.START_], [B.END_], [B.DATE_], [H.NAME_], [H.DBID_], [A.ENDACTIVITY_], [CASE WHEN D.STATE_ = ? THEN D.ASSIGNEE_ ELSE CASE WHEN (T_OP_IS, C.USERID_, NULL, 0) THEN H.ASSIGNEE_ ELSE C.USERID_ END END]), filter(nil), sort_keys([A.STATE_, ASC], [B.HTASK_, ASC], [G.LONGVAL_, ASC], [B.ACTIVITY_NAME_, ASC], [B.START_, ASC], [B.END_, ASC], [B.DATE_, ASC], [H.NAME_, ASC], [H.DBID_, ASC], [A.ENDACTIVITY_, ASC])
  12 - output([F.STRINGVAL_], [G.LONGVAL_], [A.ID_], [A.STATE_], [B.ACTIVITY_NAME_], [B.HTASK_], [D.STATE_], [B.START_], [B.END_], [B.DATE_], [H.NAME_], [H.DBID_], [A.ENDACTIVITY_], [CASE WHEN D.STATE_ = ? THEN D.ASSIGNEE_ ELSE CASE WHEN (T_OP_IS, C.USERID_, NULL, 0) THEN H.ASSIGNEE_ ELSE C.USERID_ END END]), filter(nil),
      conds(nil), nl_params_([E.DEPLOYMENT_], [CASE WHEN D.STATE_ = ? THEN D.ASSIGNEE_ ELSE CASE WHEN (T_OP_IS, C.USERID_, NULL, 0) THEN H.ASSIGNEE_ ELSE C.USERID_ END END])
  13 - output([F.STRINGVAL_], [A.ID_], [A.STATE_], [B.ACTIVITY_NAME_], [B.HTASK_], [D.STATE_], [B.START_], [B.END_], [B.DATE_], [H.NAME_], [H.DBID_], [D.ASSIGNEE_], [C.USERID_], [H.ASSIGNEE_], [A.ENDACTIVITY_], [E.DEPLOYMENT_]), filter(nil),
      conds(nil), nl_params_([B.HTASK_])
  14 - output([F.STRINGVAL_], [A.ID_], [A.STATE_], [B.ACTIVITY_NAME_], [B.HTASK_], [D.STATE_], [B.START_], [B.END_], [B.DATE_], [H.NAME_], [H.DBID_], [D.ASSIGNEE_], [H.ASSIGNEE_], [A.ENDACTIVITY_], [E.DEPLOYMENT_]), filter(nil),
      conds(nil), nl_params_([B.HTASK_])
  15 - output([F.STRINGVAL_], [A.ID_], [A.STATE_], [B.ACTIVITY_NAME_], [B.HTASK_], [B.START_], [B.END_], [B.DATE_], [H.NAME_], [H.DBID_], [H.ASSIGNEE_], [A.ENDACTIVITY_], [E.DEPLOYMENT_]), filter(nil),
      conds(nil), nl_params_([A.DBID_])
  16 - output([F.STRINGVAL_], [A.ID_], [A.STATE_], [H.NAME_], [H.DBID_], [H.ASSIGNEE_], [A.ENDACTIVITY_], [E.DEPLOYMENT_], [A.DBID_]), filter(nil),
      conds(nil), nl_params_([A.DBID_])
  17 - output([F.STRINGVAL_], [A.ID_], [A.STATE_], [A.ENDACTIVITY_], [E.DEPLOYMENT_], [A.DBID_]), filter(nil),
      conds(nil), nl_params_([E.DEPLOYMENT_])
  18 - output([A.ID_], [A.STATE_], [A.ENDACTIVITY_], [E.DEPLOYMENT_], [A.DBID_]), filter(nil),
      conds(nil), nl_params_([A.PROCDEFID_])
  19 - output([A.DBID_], [A.PROCDEFID_], [A.ID_], [A.STATE_], [A.ENDACTIVITY_]), filter(nil),
      access([A.DBID_], [A.PROCDEFID_], [A.ID_], [A.STATE_], [A.ENDACTIVITY_]), partitions(p0)
  20 - output([E.DEPLOYMENT_]), filter([E.KEY_ = ?]),
      access([E.DEPLOYMENT_], [E.KEY_]), partitions(p0)
  21 - output([F.STRINGVAL_]), filter([F.STRINGVAL_ = ?], [F.KEY_ = ?]),
      access([F.KEY_], [F.STRINGVAL_]), partitions(p0)
  22 - output([H.NAME_], [H.DBID_], [H.ASSIGNEE_]), filter(nil),
      access([H.NAME_], [H.DBID_], [H.ASSIGNEE_]), partitions(p0)
  23 - output([B.HTASK_], [B.START_], [B.END_], [B.ACTIVITY_NAME_], [B.DATE_]), filter([B.TYPE_ = ?]),
      access([B.HTASK_], [B.TYPE_], [B.START_], [B.END_], [B.ACTIVITY_NAME_], [B.DATE_]), partitions(p0)
  24 - output([D.ASSIGNEE_], [D.STATE_]), filter(nil),
      access([D.ASSIGNEE_], [D.STATE_]), partitions(p0)
  25 - output([C.USERID_]), filter(nil),
      access([C.USERID_]), partitions(p0)
  26 - output([G.LONGVAL_]), filter([? = ?], [G.KEY_ = ?]),
      access([G.KEY_], [G.LONGVAL_]), partitions(p0)

```

## 关键诊断信息

### 触发条件

SQL 有连接条件，且投影表达式中存在复杂共享表达式。

### 事前巡检

可以看下是否有连接条件和投影表达式中存在复杂共享表达式，如果存在，则进一步。

### 事后诊断

分析计划是否满足以下条件：

- 计划中存在 NLJ 算子（这里称为问题 NLJ 算子进行描述），且是非向量化和非 batch NLJ 场景。
 - 问题 NLJ 算子下压参数为复杂表达式，非简单 column。
 - 该下压表达式需要与问题 NLJ output 为共享表达式。
 - 整个问题 NLJ 算子需要能够被调用 rescan，也就是需要在 NLJ/subplan filter 这种触发 rescan 算子的右支，且有下压参数到问题 NLJ 的子计划上。
 - 在问题 NLP 算子及 rescan 算子间，需要有一个阻塞算子，将问题 NLJ 下压的的复杂表达式数据进行物化。

## 问题原因

示例中执行计划 12 号NLP 算子，下压参数为 case when 表达式，并且该表达式是 12 号 NLJ 算子的 output, 当前 NLJ 的实现，在 inner_get_next_row 实现中，获取左支数据前后，没有 clear evaluate flag，然后计算 case when 这个下压参数，并下压给 NLJ 右支，由于没有 clear evaluate flag，在 0 号算子 rescan 后，也没有清除 12 号算子中 case when 表达式上已计算标记，导致 rescan 后，12 号 NLJ 算子再进行获取左支数据计算 case when 时，不会触发实际计算，还是使用的上一次 case when 结果的数据，导致 12 号 NLJ 下压给右支的结果不对；最终导致 NLJ 执行结果不对。

可知 Nested Loop Join 算子，在获取内表数据前后，没有将标记表达式是否已经计算的标记清除，导致 Nested Loop Join 在调用 rescan 后，获取内表数据后，没有跟进新的内表数据计算下压的复杂表达式，复用了上一次内表数据计算的结果，导致下压表达式结果不对，最终导致 NLJ 执行结果不对。

## 问题的风险及影响

可能存在正确性问题。

## 影响租户

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

## 影响版本

OceanBase 数据库企业版 V3.1.2 GA（oceanbase-3.1.2-20210618150922）及之后版本、V3.2.3 GA（oceanbase-3.2.3.0-20220419）及之后版本、V3.2.4 GA（oceanbase-3.2.4.0-100000072022102819）及之后版本、V4.2.1 GA（oceanbase-4.2.1.0-100000182023092722）及之后版本、V4.2.2 GA（oceanbase-4.2.2.0-100000082024011317）及之后版本。

## 解决方法

- 升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 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 BP11（oceanbase-3.2.3.3-111000032024070822）、V3.2.4 BP8（oceanbase-3.2.4.8-108000142024041520）、V4.2.1 BP3 Hotfix4（oceanbase-4.2.1.3-103040012024011620）、V4.2.1 BP3 Hotfix5（oceanbase-4.2.1.3-103050012024012511）、V4.2.1 BP4（oceanbase-4.2.1.4-104000062024022914）、V4.2.2 BP1（oceanbase-4.2.2.1-101000012024030619）。
 - 通过绑定 Hint，改变执行计划，不走 Nested Loop Join。

## 规避方式

暂无确定的有效规避方式，需要升级到对应修复版本。

Previous

[SQL 查询中使用聚合函数下压相关问题的诊断](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000003132170)

Next

[执行计划跳变排查思路整理](https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000001140811) ![有帮助](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) 咨询热线
