1616// under the License.
1717
1818//! Criterion benchmarks for Hash Join with RightSemi/RightAnti joins with Int32 keys.
19+ //!
20+ //! ## Key Benchmark Axes
21+ //!
22+ //! - **Density**: The ratio of distinct key values to the key range span.
23+ //! For example, keys [0, 2, 4, 6, 8] have density = 5/9 ≈ 55% (5 distinct values
24+ //! in a range of 9). Density affects hash table memory layout and cache behavior.
25+ //! Lower density means keys are more spread out, leading to more cache misses.
26+ //!
27+ //! - **Hit Rate**: The percentage of probe rows that find a match in the build side.
28+ //! This controls how often the join produces output rows.
29+ //!
30+ //! Semi/anti joins can short-circuit after finding the first match, so these
31+ //! benchmarks help evaluate optimization strategies for existence checks.
1932
2033use std:: sync:: Arc ;
2134
@@ -157,6 +170,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
157170 let mut group = c. benchmark_group ( "hash_join_semi_anti" ) ;
158171
159172 // Build side: 100K rows, Probe side: 1M rows
173+ // Matching ratio: 1:1 (build keys are unique, each probe matches at most 1 build row)
160174 let build_rows = 100_000 ;
161175 let probe_rows = 1_000_000 ;
162176
@@ -165,6 +179,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
165179 // =========================================================================
166180
167181 // RightSemi - 100% Density, 100% hit rate
182+ // Keys: 0..100K contiguous, all probe rows find a match
168183 {
169184 let left_batches = build_batches ( build_rows, build_rows, 0 , & s) ;
170185 let right_batches = build_batches ( probe_rows, build_rows, 0 , & s) ;
@@ -178,6 +193,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
178193 }
179194
180195 // RightSemi - 100% Density, 10% hit rate
196+ // Keys: 0..100K contiguous, only 10% of probe rows find a match
181197 {
182198 let left_batches = build_batches ( build_rows, build_rows, 0 , & s) ;
183199 let right_batches = build_batches ( probe_rows, build_rows * 10 , 0 , & s) ;
@@ -191,6 +207,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
191207 }
192208
193209 // RightSemi - 50% Density, 100% hit rate
210+ // Keys: 0, 2, 4, ... (sparse, multiplier=2), all probe rows find a match
194211 {
195212 let left_batches = build_batches_sparse ( build_rows, build_rows, 0 , 2 , & s) ;
196213 let right_batches = build_batches_sparse ( probe_rows, build_rows, 0 , 2 , & s) ;
@@ -204,6 +221,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
204221 }
205222
206223 // RightSemi - 50% Density, 10% hit rate
224+ // Keys: 0, 2, 4, ... (sparse), only 10% of probe rows find a match
207225 {
208226 let left_batches = build_batches_sparse ( build_rows, build_rows, 0 , 2 , & s) ;
209227 let right_batches = build_batches_sparse ( probe_rows, build_rows * 10 , 0 , 2 , & s) ;
@@ -217,6 +235,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
217235 }
218236
219237 // RightSemi - 10% Density, 100% hit rate
238+ // Keys: 0, 10, 20, ... (very sparse, multiplier=10), all probe rows find a match
220239 {
221240 let left_batches = build_batches_sparse ( build_rows, build_rows, 0 , 10 , & s) ;
222241 let right_batches = build_batches_sparse ( probe_rows, build_rows, 0 , 10 , & s) ;
@@ -230,6 +249,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
230249 }
231250
232251 // RightSemi - 10% Density, 10% hit rate
252+ // Keys: 0, 10, 20, ... (very sparse), only 10% of probe rows find a match
233253 {
234254 let left_batches = build_batches_sparse ( build_rows, build_rows, 0 , 10 , & s) ;
235255 let right_batches = build_batches_sparse ( probe_rows, build_rows * 10 , 0 , 10 , & s) ;
@@ -247,6 +267,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
247267 // =========================================================================
248268
249269 // RightAnti - 100% Density, 100% hit rate (no output)
270+ // Keys: 0..100K contiguous, all probe rows find a match -> no output
250271 {
251272 let left_batches = build_batches ( build_rows, build_rows, 0 , & s) ;
252273 let right_batches = build_batches ( probe_rows, build_rows, 0 , & s) ;
@@ -260,6 +281,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
260281 }
261282
262283 // RightAnti - 100% Density, 10% hit rate (90% output)
284+ // Keys: 0..100K contiguous, only 10% of probe rows find a match -> 90% output
263285 {
264286 let left_batches = build_batches ( build_rows, build_rows, 0 , & s) ;
265287 let right_batches = build_batches ( probe_rows, build_rows * 10 , 0 , & s) ;
@@ -273,6 +295,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
273295 }
274296
275297 // RightAnti - 50% Density, 100% hit rate (no output)
298+ // Keys: 0, 2, 4, ... (sparse), all probe rows find a match -> no output
276299 {
277300 let left_batches = build_batches_sparse ( build_rows, build_rows, 0 , 2 , & s) ;
278301 let right_batches = build_batches_sparse ( probe_rows, build_rows, 0 , 2 , & s) ;
@@ -286,6 +309,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
286309 }
287310
288311 // RightAnti - 50% Density, 10% hit rate (90% output)
312+ // Keys: 0, 2, 4, ... (sparse), only 10% of probe rows find a match -> 90% output
289313 {
290314 let left_batches = build_batches_sparse ( build_rows, build_rows, 0 , 2 , & s) ;
291315 let right_batches = build_batches_sparse ( probe_rows, build_rows * 10 , 0 , 2 , & s) ;
@@ -299,6 +323,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
299323 }
300324
301325 // RightAnti - 10% Density, 100% hit rate (no output)
326+ // Keys: 0, 10, 20, ... (very sparse), all probe rows find a match -> no output
302327 {
303328 let left_batches = build_batches_sparse ( build_rows, build_rows, 0 , 10 , & s) ;
304329 let right_batches = build_batches_sparse ( probe_rows, build_rows, 0 , 10 , & s) ;
@@ -312,6 +337,7 @@ fn bench_hash_join_semi_anti(c: &mut Criterion) {
312337 }
313338
314339 // RightAnti - 10% Density, 10% hit rate (90% output)
340+ // Keys: 0, 10, 20, ... (very sparse), only 10% of probe rows find a match -> 90% output
315341 {
316342 let left_batches = build_batches_sparse ( build_rows, build_rows, 0 , 10 , & s) ;
317343 let right_batches = build_batches_sparse ( probe_rows, build_rows * 10 , 0 , 10 , & s) ;
0 commit comments