Skip to content

fix: count each probe row once in HashJoinExec probe_hit_rate and avg_fanout - #25272

Merged
jayzhan211 merged 1 commit into
apache:mainfrom
CuteChuanChuan:issue-25077/hashjoinexect-metric-overcounts
Sep 15, 2026
Merged

jayzhan211 merged 1 commit into
apache:mainfrom
CuteChuanChuan:issue-25077/hashjoinexect-metric-overcounts

Conversation

@CuteChuanChuan

@CuteChuanChuan CuteChuanChuan commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

EXPLAIN ANALYZE reports probe_hit_rate and avg_fanout of HashJoinExec too low whenever a probe batch produces more than batch_size output rows, e.g. when the build side has many duplicate keys. Both metrics are defined per probe row, but their counters were updated once per output chunk.

What changes are included in this PR?

  • probe_hit_rate total: added only on the first chunk of each probe batch (state.offset == (0, None)), the same first-chunk check that process_probe_batch already uses for correlated null-aware LeftMark.
  • probe_hit_rate part and avg_fanout total: a new ProcessProbeBatchState::matched_probe_idx records the last probe index counted so far. count_new_matched_probe_rows does not count a chunk's first index again if it equals that value. Empty chunks leave it unchanged.
  • Existing state is not reused: joined_probe_idx is tracked after the join filter, while these metrics are defined before it, and the lookup offset can point at a probe row that has not been counted yet.

What is the testing strategy for this PR?

Two new tests in hash_join/exec.rs, each run over hash_join_exec_configs (batch sizes 8192/10/5/2/1, perfect hash join on and off):

  • join_probe_metrics_count_each_probe_row_once: duplicate build keys, so one probe row's matches are split across chunks. Fails without this change for batch sizes 5, 2 and 1.
  • join_probe_metrics_count_probe_row_starting_new_chunk: unique build keys, so chunks split between probe rows. It guards against deduplicating by the lookup offset: comparing against offset.0 (on non-first chunks) instead makes this test fail for batch sizes 2 and 1, while the first test still passes.

Are there any user-facing changes?

probe_hit_rate and avg_fanout shown by EXPLAIN ANALYZE are now correct when a probe batch is processed in several chunks. No public API changes.

…_fanout

- `probe_hit_rate` added the batch's row count to its total on every chunk.
- A probe row whose matches span a chunk boundary was counted in both chunks, inflating the `probe_hit_rate` part and the `avg_fanout` total. `ProcessProbeBatchState` now tracks the last counted probe index.
@github-actions github-actions Bot added the physical-plan Changes to the physical-plan crate label Sep 13, 2026
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.96970% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 81.89%. Comparing base (e4c4fa4) to head (3cfbb98).

Files with missing lines Patch % Lines
...tafusion/physical-plan/src/joins/hash_join/exec.rs 92.30% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #25272      +/-   ##
==========================================
- Coverage   81.89%   81.89%   -0.01%     
==========================================
  Files        1133     1133              
  Lines      424660   424685      +25     
  Branches   424660   424685      +25     
==========================================
+ Hits       347765   347781      +16     
- Misses      56283    56290       +7     
- Partials    20612    20614       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@CuteChuanChuan

Copy link
Copy Markdown
Contributor Author

Hi @jayzhan211 ,

could you PTAL when you have a chance. Thanks! 🙏

@jayzhan211 jayzhan211 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @CuteChuanChuan LGTM!

@jayzhan211
jayzhan211 added this pull request to the merge queue Sep 15, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 15, 2026
@jayzhan211
jayzhan211 added this pull request to the merge queue Sep 15, 2026
Merged via the queue into apache:main with commit fe28a2b Sep 15, 2026
43 checks passed
@CuteChuanChuan
CuteChuanChuan deleted the issue-25077/hashjoinexect-metric-overcounts branch September 15, 2026 14:56
@CuteChuanChuan

Copy link
Copy Markdown
Contributor Author

Hi @jayzhan211 ,
thanks for the review! Working on this raised two follow-up ideas, and I opened issues for them: #25332 (making MapOffset an enum) and #25333 (test coverage for join metrics). I'd appreciate your thoughts there if you have time.

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

Labels

physical-plan Changes to the physical-plan crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HashJoinExec probe_hit_rate metric overcounts probe rows when a probe batch is processed in several chunks

3 participants