Skip to content

[CBRD-27138] Report the optimizer giving up on a join too wide to index - #7724

Open
soheejung-cs wants to merge 2 commits into
CUBRID:developfrom
soheejung-cs:feature/CBRD-27138-report-optimizer-giveup
Open

[CBRD-27138] Report the optimizer giving up on a join too wide to index#7724
soheejung-cs wants to merge 2 commits into
CUBRID:developfrom
soheejung-cs:feature/CBRD-27138-report-optimizer-giveup

Conversation

@soheejung-cs

Copy link
Copy Markdown
Contributor

http://jira.cubrid.org/browse/CBRD-27138

Purpose

qo_discover_partitions ()는 한 파티션의 노드 수가 _WORDSIZE - 2 - LOG2_SIZEOF_POINTER(= 27)를 넘으면 QO_ABORT로 최적화 전체를 중단한다. 질의는 구문 순서 그대로의 조인 플랜으로 실행되므로 결과는 정상이지만 비용 기반 조인 순서·인덱스 선택이 통째로 사라진다.

문제는 그것이 사용자에게 전혀 알려지지 않는다는 점이었다. 27테이블 질의는 최적화되고 28테이블 질의는 최적화되지 않는데, 관측 가능한 차이는 "플랜 덤프가 안 나온다"는 것뿐이고 그마저 덤프를 껐을 때와 구분되지 않는다. BI 도구·ORM이 만드는 질의에서 실제로 28테이블 경계를 넘나들기 때문에, 27→28에서 성능이 절벽처럼 떨어지고 원인을 짚을 단서가 없었다.

이 PR은 한계를 넘겼다는 사실을 보이게 만든다. 한계 자체는 그대로다.

Implementation

1. abort 지점에서 알림 기록 (query_graph.c)

er_set (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_QO_SET_SIZE_EXCEEDED, 0);
er_log_debug (ARG_FILE_LINE, "cost-based optimization skipped: a join partition has %d tables, "
              "more than the %d the join_info vector can index\n", ...);
  • ER_QO_SET_SIZE_EXCEEDED(-470)는 정의만 있고 지금까지 아무 곳에서도 쓰이지 않던 코드이고, 메시지가 Query involves too many items for optimizer.로 이 상황 그대로다. 새 에러코드를 추가하지 않았다(6곳 갱신·CCI 동기화 불필요).
  • severity는 notification이다. warning으로 하면 error_log_warning이 기본 off라(error_manager.c의 severity 필터) 기본 설정에서 로그에 남지 않아 "조용히 비활성화"라는 증상이 그대로 남는다. notification은 기본 기록되고, 클라이언트에 에러 상태를 남기지 않으므로 질의는 이전과 똑같이 구문 순서 플랜으로 실행된다.
  • 노드 수와 한계값은 디버그 로그로 함께 남긴다.

2. 플랜 덤프에 사유 출력 (xasl_generation.c)

덤프를 요청했는데(SET OPTIMIZATION LEVEL) 플랜이 없으면 섹션을 생략하지 않고 다음을 출력한다.

Query plan: (not generated -- cost-based optimization was skipped for this query)

이 경로는 노드 한계 외에 할당 실패·내부 assertion 실패로 최적화가 중단된 경우도 함께 덮는다.

Verification

JIRA 재현 절차대로 27·28테이블 체인 조인(각 1행, PK, 통계 수집), release 빌드, SET OPTIMIZATION LEVEL 513:

케이스 플랜 덤프 에러 로그
27테이블 Query plan: + 플랜 본문 (기존과 동일) 없음 (기존과 동일)
28테이블 Query plan: (not generated -- cost-based optimization was skipped for this query) NOTIFICATION ... CODE = -470 / Query involves too many items for optimizer.

두 경우 모두 질의는 정상 수행되고 결과 행도 동일하다(28테이블은 이전처럼 구문 순서 플랜).

Remarks

  • 한계(27)는 이 PR에서 바뀌지 않는다. 원인은 탐색 비용이 아니라 DP 인덱싱의 표현력이다 — join_info 벡터를 파티션 노드의 부분집합 비트마스크로 색인하므로 항목 수가 2**nodes이고, 바이트 크기가 signed int를 넘는 지점이 27이다. 한계를 없애려면 이 벡터를 해시맵으로 바꿔야 하고, 그것은 별도 변경이다.
  • CBRD-27142(PR [CBRD-27142] Bound the partial join search by an enumeration budget, not a table-count staircase #7721, join_unit 탐색 예산제)와는 무관하다. 그 변경은 qo_search_partition_join () 안의 탐색 깊이 산정이고, 이 abort는 그 함수가 호출되기 전 파티션 발견 단계에서 일어난다. 28테이블 질의는 예산 계산에 도달조차 하지 않는다.
  • 알림이 기록되는 것 외에 동작 변화는 없으므로 기존 회귀 테스트에 영향이 없어야 한다. 다만 SET OPTIMIZATION LEVEL로 덤프를 켠 상태에서 최적화가 중단되는 질의를 가진 케이스가 있다면 그 답안에 한 줄이 추가된다(현재 테스트 스위트에는 28테이블 이상 조인 케이스가 없다).

qo_discover_partitions () aborts optimization when a partition holds
more nodes than the join_info vector can index -- the vector is indexed
by a subset bitmask of the partition's nodes, so it holds 2**nodes
entries and its byte size stops fitting in a signed int past
_WORDSIZE - 2 - LOG2_SIZEOF_POINTER (27) nodes. The statement then runs
with the syntactic join order, which is a legitimate fallback, but it
happened without a word to the user: a 28-table query silently lost
cost-based join ordering and index selection where a 27-table one kept
it, and the only observable difference was that the plan dump printed
nothing.

Report it in the two places a user looks. The abort now raises the
existing (until now unused) ER_QO_SET_SIZE_EXCEEDED warning -- 'Query
involves too many items for optimizer.' -- so the error log records it,
with the node count and the limit in the debug log beside it. And when a
plan dump was requested but no plan exists, the dump says the plan was
not generated instead of omitting the section, so its absence is no
longer indistinguishable from the dump being off.

The limit itself is unchanged: removing it needs the subset-indexed
join_info vector replaced by a hash map, which is a separate change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJG3W9JhvjYKRe5GUzbb6m
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown

❌ TC Merge Gate — Merge Blocked

One or more TC PRs are still open. Please merge or close them before merging this PR.

TC Repositories & Branches:

  • cubrid-testcases: TC PR tc/pr-7724 is open (draft) — must be merged or closed first
  • cubrid-testcases-private-ex: TC PR tc/pr-7724 is open (draft) — must be merged or closed first

Steps to unblock:

  1. Merge or close all TC PRs listed above.
  2. Re-run this check: Actions tab → TC Merge Gate → Re-run failed jobs

@github-actions

Copy link
Copy Markdown

🧪 TC Test Environment Ready

CircleCI Testing:

  • CircleCI will automatically test using the branches below.

TC Repositories & Branches:

Next Steps:

  1. Wait for CircleCI tests to complete
  2. If CircleCI tests failed, please check the test results and fix the issues.
  3. When ready to merge this PR, please merge the TC PR first, then merge this PR.

@greptile-apps

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "[CBRD-27138] Report the optimizer giving..." | Re-trigger Greptile

Comment thread src/optimizer/query_graph.c Outdated
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@soheejung-cs

Copy link
Copy Markdown
Contributor Author

/run all

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant