Skip to content

[fix](fe) Fix semi join constraint matching for leading hint#65205

Merged
starocean999 merged 1 commit into
apache:masterfrom
shuke987:fix-leading-hint-semi-join
Jul 9, 2026
Merged

[fix](fe) Fix semi join constraint matching for leading hint#65205
starocean999 merged 1 commit into
apache:masterfrom
shuke987:fix-leading-hint-semi-join

Conversation

@shuke987

@shuke987 shuke987 commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Issue Number: N/A

Related PR: N/A

Problem Summary:

A muted FE UT failure in DistributeHintTest.testLeading exposed that leading hint can match a semi/anti join constraint too early or with extra tables on the constrained side. The old left-side check in LeadingHint#getJoinConstraint used the same subset predicate on both sides of the condition, making that guard always false, and the check only covered semi joins with the original right side.

This patch makes semi/anti constraints match only after the minimal left and right hands are both present in the current join. It also chooses the constrained side by join direction: left semi/anti requires the original right side to match a child exactly, while right semi/anti requires the original left side to match a child exactly. Any child that partially overlaps the constrained side without equaling it is rejected, so a composite constrained side can not be split across both join children. The retained side can still match by its minimal hand, allowing unrelated retained-side joins to be applied later. Unit tests cover left/right semi/anti cases, including early constrained-side matches, extra-table matches, composite constrained-side splits, and composite retained-side/min-hand matches.

Release note

None

Check List (For Author)

  • Test
    • Unit Test
    • Regression test
    • Manual test
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason

./run-fe-ut.sh --run org.apache.doris.nereids.hint.LeadingHintTest

  • Behavior changed:

    • No.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@shuke987

shuke987 commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator Author

run feut

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 100.00% (1/1) 🎉
Increment coverage report
Complete coverage report

@shuke987

shuke987 commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29320 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 6d96b4bbcf42ab5e7533c58458eb0a0d63ea1a75, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17618	3986	3954	3954
q2	2041	314	193	193
q3	10263	1364	810	810
q4	4697	464	347	347
q5	7546	850	567	567
q6	181	169	140	140
q7	741	841	614	614
q8	9822	1584	1639	1584
q9	6301	4350	4399	4350
q10	6807	1819	1500	1500
q11	509	345	321	321
q12	725	549	433	433
q13	18082	3356	2759	2759
q14	265	258	243	243
q15	q16	780	769	709	709
q17	935	911	962	911
q18	6781	5746	5553	5553
q19	1411	1234	1111	1111
q20	759	641	562	562
q21	5827	2569	2358	2358
q22	429	355	301	301
Total cold run time: 102520 ms
Total hot run time: 29320 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4379	4275	4303	4275
q2	317	321	216	216
q3	4577	4967	4382	4382
q4	2049	2131	1368	1368
q5	4398	4335	4293	4293
q6	227	176	126	126
q7	1726	1929	1796	1796
q8	2570	2249	2137	2137
q9	7941	7778	7803	7778
q10	4716	4701	4241	4241
q11	615	439	369	369
q12	772	762	544	544
q13	3440	3525	2939	2939
q14	292	298	289	289
q15	q16	718	769	655	655
q17	1367	1332	1344	1332
q18	8070	7281	7281	7281
q19	1136	1087	1084	1084
q20	2211	2220	1959	1959
q21	5272	4608	4497	4497
q22	521	462	433	433
Total cold run time: 57314 ms
Total hot run time: 51994 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 174370 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 6d96b4bbcf42ab5e7533c58458eb0a0d63ea1a75, data reload: false

query5	4298	655	486	486
query6	463	222	200	200
query7	4862	592	338	338
query8	344	195	167	167
query9	8735	4074	4076	4074
query10	471	348	314	314
query11	5804	2341	2165	2165
query12	178	103	100	100
query13	1279	580	454	454
query14	6290	5313	4992	4992
query14_1	4320	4397	4334	4334
query15	228	203	182	182
query16	1033	468	462	462
query17	1065	734	618	618
query18	2456	477	355	355
query19	208	195	158	158
query20	114	108	104	104
query21	241	170	135	135
query22	13606	13615	13363	13363
query23	17310	16462	16043	16043
query23_1	16241	16236	16198	16198
query24	7479	1793	1326	1326
query24_1	1334	1325	1301	1301
query25	571	451	395	395
query26	1335	346	213	213
query27	2652	580	371	371
query28	4434	2026	2048	2026
query29	1087	638	511	511
query30	337	265	230	230
query31	1113	1099	997	997
query32	110	65	61	61
query33	542	333	261	261
query34	1344	1134	655	655
query35	749	786	703	703
query36	1437	1427	1334	1334
query37	170	123	98	98
query38	1912	1753	1698	1698
query39	1008	969	946	946
query39_1	912	924	923	923
query40	259	164	142	142
query41	68	66	63	63
query42	95	92	96	92
query43	329	339	286	286
query44	1472	766	776	766
query45	197	189	176	176
query46	1067	1205	767	767
query47	2363	2336	2195	2195
query48	367	433	292	292
query49	575	425	314	314
query50	1050	424	332	332
query51	4404	4446	4507	4446
query52	87	87	76	76
query53	265	277	210	210
query54	290	228	224	224
query55	77	73	68	68
query56	303	287	284	284
query57	1433	1390	1308	1308
query58	268	260	252	252
query59	1558	1661	1471	1471
query60	291	266	277	266
query61	153	145	148	145
query62	702	646	586	586
query63	242	208	210	208
query64	2532	773	602	602
query65	4859	4792	4767	4767
query66	1826	510	380	380
query67	29599	29441	29313	29313
query68	3225	1577	992	992
query69	417	295	264	264
query70	1095	954	947	947
query71	355	360	349	349
query72	2889	2641	2355	2355
query73	861	826	437	437
query74	5111	4991	4775	4775
query75	2619	2582	2229	2229
query76	2341	1192	800	800
query77	365	384	297	297
query78	12653	12542	11840	11840
query79	1400	1219	748	748
query80	882	556	466	466
query81	538	325	287	287
query82	584	165	126	126
query83	367	322	297	297
query84	294	160	131	131
query85	985	601	495	495
query86	406	296	293	293
query87	1841	1838	1743	1743
query88	3775	2823	2771	2771
query89	466	425	357	357
query90	1908	206	200	200
query91	203	189	157	157
query92	67	64	55	55
query93	1524	1687	959	959
query94	627	362	321	321
query95	771	496	476	476
query96	1044	762	361	361
query97	2678	2700	2612	2612
query98	218	202	204	202
query99	1165	1145	1031	1031
Total cold run time: 258923 ms
Total hot run time: 174370 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.25 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 6d96b4bbcf42ab5e7533c58458eb0a0d63ea1a75, data reload: false

query1	0.01	0.01	0.01
query2	0.09	0.05	0.06
query3	0.26	0.14	0.13
query4	1.60	0.13	0.14
query5	0.24	0.25	0.23
query6	1.27	1.03	1.03
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.40	0.31	0.32
query10	0.59	0.56	0.58
query11	0.19	0.14	0.14
query12	0.18	0.15	0.14
query13	0.49	0.48	0.50
query14	1.02	0.98	1.00
query15	0.63	0.61	0.60
query16	0.33	0.33	0.33
query17	1.14	1.15	1.15
query18	0.22	0.21	0.21
query19	2.10	1.93	2.00
query20	0.02	0.01	0.01
query21	15.44	0.23	0.15
query22	4.92	0.06	0.05
query23	16.11	0.31	0.11
query24	2.99	0.46	0.32
query25	0.12	0.04	0.05
query26	0.73	0.20	0.14
query27	0.03	0.04	0.04
query28	3.52	0.88	0.54
query29	12.49	4.33	3.46
query30	0.27	0.16	0.14
query31	2.77	0.60	0.31
query32	3.21	0.59	0.49
query33	3.22	3.28	3.23
query34	15.54	4.20	3.47
query35	3.55	3.50	3.52
query36	0.56	0.44	0.43
query37	0.08	0.07	0.07
query38	0.06	0.04	0.04
query39	0.04	0.03	0.03
query40	0.17	0.17	0.15
query41	0.08	0.04	0.03
query42	0.04	0.02	0.03
query43	0.05	0.03	0.04
Total cold run time: 96.87 s
Total hot run time: 25.25 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 100.00% (1/1) 🎉
Increment coverage report
Complete coverage report

@shuke987

shuke987 commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions github-actions Bot 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.

Automated review result: request changes.

I found two correctness gaps in the leading-hint semi/anti constraint fix. The new unit test still misses a semi-join order where the RHS is joined before the original LHS exists, and the code guard still does not cover anti joins or direct right semi/right anti constraints with the correct exact side.

Critical checkpoint conclusions:

  • Goal and tests: the PR is small and focused, and it adds a targeted JUnit test, but the current change does not fully accomplish the stated leading-hint constraint goal because related semi/anti paths remain valid matches.
  • Parallel paths: not complete. Left anti and direct right semi/right anti paths remain uncovered by the new check.
  • Concurrency, lifecycle, config, persistence, data writes, FE-BE protocol, and observability: not applicable to this local FE planner logic change.
  • Test validation: I did not run FE tests because this checkout is missing thirdparty/installed/bin/protoc and thirdparty/installed, so the repo instructions make local FE build/test execution invalid here.
  • User focus: no additional user-provided review focus was supplied.

Subagent conclusions: TSC-1 was accepted as M-1 and submitted as an inline test coverage/correctness comment. OR-1 and OR-2 were accepted and merged into M-2 as one inline code comment. Convergence round 1 found OR-2, so the ledger/comment set was updated; convergence round 2 ended with both optimizer-rewrite and tests-session-config reporting NO_NEW_VALUABLE_FINDINGS.

if (joinConstraint.getJoinType().isSemiJoin()) {
if (LongBitmap.isSubset(joinConstraint.getRightHand(), leftTableBitmap)
&& !LongBitmap.isSubset(joinConstraint.getRightHand(), leftTableBitmap)) {
&& !joinConstraint.getRightHand().equals(leftTableBitmap)) {

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.

This guard is still too narrow. First, it only runs for isSemiJoin(), so A LEFT ANTI JOIN B can still match a leading step like (B JOIN C) JOIN A, skip this block, take the reversed branch below, and become a RIGHT_ANTI_JOIN that tests absence from B JOIN C instead of absence from B. Second, direct right semi/right anti constraints need the exact check on the original left/filtering side, not rightHand: for A RIGHT SEMI JOIN B, getJoinConstraint(A | B | C, A | C, B) passes this check because rightHand == B, then applies the semi test against A JOIN C. Please make the exact-side check cover anti joins and choose the constrained side by join direction, with left/right semi and anti unit cases.

@shuke987
shuke987 force-pushed the fix-leading-hint-semi-join branch from 6d96b4b to a703e99 Compare July 6, 2026 03:15
@shuke987

shuke987 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

/review

@shuke987

shuke987 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

run buildall

@github-actions github-actions Bot 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.

Automated review result: requesting changes.

I reviewed the two changed files plus the relevant LeadingHint, CollectJoinConstraint, bitmap, and join-output paths. The patch fixes the earlier one-child constrained-side cases, but one remaining semi/anti leading-hint shape can still produce a semantically invalid plan; see the inline comment.

Critical checkpoint conclusions:

  • Goal/test: the goal is to make semi/anti leading constraints match only valid side shapes. The added unit tests cover simple one-table sides, but not the composite full-side/min-side divergence that remains broken.
  • Scope: the change is narrow and focused on LeadingHint matching plus a unit test.
  • Concurrency, lifecycle, config, persistence, compatibility, and data-write paths: not involved.
  • Parallel paths: checked left/right semi and anti matching. The remaining issue is a parallel composite constrained-side path where full side and min side differ.
  • Tests/validation: did not run FE UT because this runner lacks thirdparty/installed and executable thirdparty/installed/bin/protoc. git diff --check on the changed files passed.
  • User focus: no additional user-provided review focus.

Subagent conclusions: optimizer-rewrite produced OPT-001, accepted as MAIN-001 and submitted inline. tests-session-config produced TSC-001, a duplicate test-coverage note folded into MAIN-001. Convergence round C1 ended with both optimizer-rewrite and tests-session-config reporting NO_NEW_VALUABLE_FINDINGS for the same final ledger/comment set.


Long constrainedSide = joinConstraint.getJoinType().isRightSemiOrAntiJoin()
? joinConstraint.getLeftHand() : joinConstraint.getRightHand();
if (LongBitmap.isSubset(constrainedSide, leftTableBitmap)

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.

This still accepts cases where the constrained semi/anti side is split across both candidate children. For example, a collected constraint from (A CROSS JOIN C) RIGHT SEMI JOIN B ON A.k = B.k has full leftHand = A|C and rightHand = B, but minLeftHand can be only A. With a leading step getJoinConstraint(A|B|C, A, B|C), constrainedSide is A|C; it is not a subset of either child, so both exact checks are skipped and the later minLeftHand/minRightHand match returns RIGHT_SEMI_JOIN. That rewrites the join as A RIGHT SEMI (B CROSS C), whose output is the whole right child B|C, while the original right semi join outputs only B and uses all of A|C only for existence testing. Please reject any child that partially overlaps the constrained side without equaling it, and add unit coverage where leftHand/rightHand is composite but the corresponding min*Hand is narrower.

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29836 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit a703e990e8515d9f7cab5a251281918a991fac68, data reload: false

------ Round 1 ----------------------------------
============================================
q1	18028	4403	4202	4202
q2	2040	317	201	201
q3	10265	1365	822	822
q4	4678	478	335	335
q5	7543	849	580	580
q6	182	167	140	140
q7	761	862	614	614
q8	9471	1629	1637	1629
q9	6172	4465	4488	4465
q10	6800	1794	1525	1525
q11	490	337	310	310
q12	736	553	432	432
q13	18104	3401	2734	2734
q14	274	260	242	242
q15	q16	784	794	718	718
q17	1714	1167	891	891
q18	6971	5755	5617	5617
q19	1550	1271	1109	1109
q20	750	661	520	520
q21	6030	2666	2452	2452
q22	434	354	298	298
Total cold run time: 103777 ms
Total hot run time: 29836 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4489	4460	4386	4386
q2	296	311	209	209
q3	4602	4947	4416	4416
q4	2088	2159	1379	1379
q5	4428	4309	4370	4309
q6	327	270	159	159
q7	2110	1817	1575	1575
q8	2529	2327	2148	2148
q9	7943	7806	7910	7806
q10	4751	4721	4536	4536
q11	642	410	374	374
q12	790	775	552	552
q13	3216	3598	3015	3015
q14	318	307	277	277
q15	q16	707	729	651	651
q17	1373	1356	1351	1351
q18	8112	7399	6921	6921
q19	1119	1097	1155	1097
q20	2233	2219	1932	1932
q21	5301	4732	4567	4567
q22	544	464	396	396
Total cold run time: 57918 ms
Total hot run time: 52056 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 174467 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit a703e990e8515d9f7cab5a251281918a991fac68, data reload: false

query5	4336	658	487	487
query6	473	217	205	205
query7	4871	593	356	356
query8	333	195	178	178
query9	8739	4159	4112	4112
query10	461	360	311	311
query11	5924	2358	2169	2169
query12	158	106	101	101
query13	1276	653	451	451
query14	6325	5330	5006	5006
query14_1	4342	4259	4284	4259
query15	214	198	192	192
query16	1041	466	433	433
query17	1111	719	572	572
query18	2651	482	337	337
query19	203	185	149	149
query20	110	106	107	106
query21	238	163	134	134
query22	13614	13663	13538	13538
query23	17363	16651	16253	16253
query23_1	16408	16616	16531	16531
query24	7557	1776	1287	1287
query24_1	1325	1298	1290	1290
query25	529	440	366	366
query26	1350	363	200	200
query27	2569	582	382	382
query28	4446	2040	2015	2015
query29	1098	612	508	508
query30	347	276	232	232
query31	1120	1093	989	989
query32	123	63	62	62
query33	549	320	252	252
query34	1227	1199	660	660
query35	763	787	686	686
query36	1417	1411	1187	1187
query37	156	113	96	96
query38	1899	1712	1648	1648
query39	931	952	902	902
query39_1	897	882	933	882
query40	254	167	146	146
query41	67	62	64	62
query42	93	91	91	91
query43	333	324	294	294
query44	1457	785	773	773
query45	205	191	180	180
query46	1074	1239	722	722
query47	2379	2308	2191	2191
query48	406	388	308	308
query49	577	427	326	326
query50	1113	441	345	345
query51	4399	4443	4302	4302
query52	87	85	74	74
query53	267	271	208	208
query54	276	231	212	212
query55	79	73	66	66
query56	277	313	281	281
query57	1454	1423	1296	1296
query58	272	263	252	252
query59	1594	1713	1471	1471
query60	302	284	254	254
query61	153	151	151	151
query62	702	646	592	592
query63	246	204	212	204
query64	2501	762	673	673
query65	4866	4854	4799	4799
query66	1827	530	399	399
query67	29620	29553	29423	29423
query68	3089	1573	1004	1004
query69	418	311	277	277
query70	1034	989	979	979
query71	382	323	303	303
query72	3085	2864	2444	2444
query73	865	790	419	419
query74	5104	4938	4814	4814
query75	2613	2603	2234	2234
query76	2343	1219	793	793
query77	360	384	288	288
query78	12500	12534	11878	11878
query79	1448	1169	777	777
query80	1287	551	478	478
query81	549	326	273	273
query82	626	157	119	119
query83	365	325	294	294
query84	290	166	132	132
query85	981	598	505	505
query86	442	315	280	280
query87	1849	1825	1746	1746
query88	3799	2827	2784	2784
query89	462	411	357	357
query90	1902	194	204	194
query91	199	192	161	161
query92	62	61	57	57
query93	1682	1465	987	987
query94	719	361	315	315
query95	769	486	561	486
query96	1074	814	364	364
query97	2675	2719	2540	2540
query98	225	206	205	205
query99	1188	1183	1045	1045
Total cold run time: 260122 ms
Total hot run time: 174467 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.4 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit a703e990e8515d9f7cab5a251281918a991fac68, data reload: false

query1	0.00	0.00	0.00
query2	0.10	0.05	0.05
query3	0.26	0.14	0.17
query4	1.61	0.15	0.13
query5	0.25	0.23	0.22
query6	1.29	1.09	1.09
query7	0.04	0.01	0.01
query8	0.06	0.04	0.04
query9	0.38	0.32	0.34
query10	0.57	0.57	0.58
query11	0.20	0.14	0.16
query12	0.18	0.14	0.14
query13	0.48	0.48	0.47
query14	1.02	1.00	1.03
query15	0.61	0.60	0.61
query16	0.33	0.34	0.31
query17	1.11	1.15	1.10
query18	0.24	0.22	0.22
query19	2.10	1.93	2.03
query20	0.02	0.02	0.01
query21	15.43	0.22	0.14
query22	4.87	0.06	0.05
query23	16.06	0.32	0.12
query24	3.13	0.44	0.32
query25	0.11	0.06	0.05
query26	0.73	0.21	0.16
query27	0.05	0.04	0.03
query28	3.53	0.91	0.57
query29	12.48	4.28	3.45
query30	0.27	0.15	0.15
query31	2.78	0.61	0.33
query32	3.22	0.61	0.49
query33	3.26	3.22	3.18
query34	15.61	4.25	3.57
query35	3.51	3.53	3.59
query36	0.58	0.44	0.42
query37	0.09	0.07	0.07
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.17	0.16	0.15
query41	0.09	0.03	0.02
query42	0.03	0.02	0.02
query43	0.04	0.04	0.03
Total cold run time: 96.98 s
Total hot run time: 25.4 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 50.00% (7/14) 🎉
Increment coverage report
Complete coverage report

@shuke987
shuke987 force-pushed the fix-leading-hint-semi-join branch from a703e99 to 858a26a Compare July 8, 2026 06:17
@shuke987

shuke987 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

/review

@shuke987

shuke987 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

run buildall

@github-actions github-actions Bot 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.

Automated review result: requesting changes.

I reviewed the current head 858a26a10a8dd5a62bb5a0e36ec61d960d572f12, the two changed files, existing review threads, and the surrounding CollectJoinConstraint / LeadingHint generation path. The latest patch fixes the earlier split constrained-side cases, but it also over-constrains semi/anti matching by requiring the full retained side to be present before a constraint can match. That rejects valid leading orders where only the retained side's minimal hand is needed and unrelated retained-side inner joins can be applied later; see the inline comment.

Critical checkpoint conclusions:

  • Goal and tests: the PR is focused on semi/anti leading-hint constraint matching and adds targeted JUnit coverage, but the current code does not fully accomplish the goal because composite retained-side/min-hand cases are not covered and can now be rejected incorrectly.
  • Scope: the code change is small and localized to LeadingHint.getJoinConstraint plus a focused unit test.
  • Parallel paths: checked left/right semi and anti paths. Existing prior threads cover missing retained-side presence, anti/right-side exactness, and split constrained-side matching; this remaining issue is a distinct retained-side over-rejection path.
  • Concurrency, lifecycle, config/session propagation, persistence, data writes, FE-BE protocol, and observability: not involved in this local FE planner logic change.
  • Test validation: I did not run FE UTs because this runner lacks thirdparty/installed and executable thirdparty/installed/bin/protoc, and fe/AGENTS.md says to stop FE builds when protoc is missing. I checked the GitHub patch for added-line trailing whitespace and >120-character added lines; both checks passed.
  • User focus: no additional user-provided review focus was supplied.

Subagent conclusions: optimizer-rewrite and tests-session-config produced no initial candidate findings. The main pass accepted MAIN-001 as the only inline comment. Convergence round C1 sent the final ledger/comment set containing MAIN-001 to both live subagents, and both replied NO_NEW_VALUABLE_FINDINGS for that same unchanged set.

if (LongBitmap.isSubset(joinConstraint.getRightHand(), leftTableBitmap)
&& !LongBitmap.isSubset(joinConstraint.getRightHand(), leftTableBitmap)) {
if (joinConstraint.getJoinType().isSemiOrAntiJoin()) {
if (!LongBitmap.isSubset(joinConstraint.getLeftHand(), joinTableBitmap)

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.

This check now requires both full original hands to be present before a semi/anti constraint can match, which rejects legal orders where the retained side contains tables that can be joined later. A reduced plan is:

(A INNER JOIN C) LEFT SEMI JOIN B ON A.k = B.k

CollectJoinConstraint records this as leftHand = A|C, rightHand = B, but the minimal hands are only minLeftHand = A and minRightHand = B. The existing min-hand branch below would allow the valid leading step getJoinConstraint(A|B, A, B) so the generated plan can do (A LEFT SEMI B) INNER JOIN C; the A-C filter is still applied at the later join. With this new guard, leftHand = A|C is not a subset of the current joinTableBitmap = A|B, so the constraint is skipped and the leading hint is unnecessarily treated as unavailable. Please keep the full/exact requirement on the constrained filtering side, but let the retained side continue to use the existing minLeftHand/minRightHand logic, with unit coverage where the retained side is composite.

### What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary: Leading hint may match a semi join constraint when the semi join right-hand side is only a subset of one candidate child. The left-side check used the same subset predicate on both sides of the condition, making it always false. This can let an invalid leading order apply or reverse a semi join constraint even when the semi right-hand side is already joined with extra tables. Fix the check to require the semi right-hand side to match the child bitmap exactly, and add a unit test for the exact-match requirement.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.nereids.hint.LeadingHintTest
- Behavior changed: No
- Does this need documentation: No
@shuke987
shuke987 force-pushed the fix-leading-hint-semi-join branch from 858a26a to 2ca7ced Compare July 8, 2026 06:44
@shuke987

shuke987 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions github-actions Bot 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.

Automated review completed for head 2ca7ced274ca3bd29bbe275c3cd39e1f1e6b5080.

I reviewed the changed leading-hint constraint logic and the new LeadingHintTest coverage. I did not find any new inline issue to add beyond the existing review threads; the current patch appears to address the previously raised semi/anti constrained-side cases.

Critical checkpoints:

  • Goal/test: The change targets semi/anti leading-hint constraint matching. The code now uses min hands for presence and exact full constrained-side overlap, and the added unit tests cover left/right semi and anti joins, composite constrained-side splits, and retained-side min-hand matching.
  • Scope: The patch is narrow and focused on LeadingHint.getJoinConstraint plus direct unit coverage.
  • Concurrency/lifecycle/config/persistence/protocol/security: Not involved.
  • Parallel paths: Left/right semi and anti paths were checked; the earlier anti/right-direction and composite-side concerns are covered by existing threads and by the current head.
  • Test status: I did not run local FE UT because this checkout is missing thirdparty/installed/bin/protoc, which the FE instructions require before building. PR CheckStyle is passing; several external regression checks are still pending.
  • Performance/observability: The added bitmap checks are small per-constraint operations; no additional observability is needed for this planner-only fix.

User focus: No additional user-provided focus points were supplied.

Subagent conclusions: optimizer-rewrite and tests-session-config both found no new valuable candidates beyond existing threads. Convergence round 1 ended with both subagents replying NO_NEW_VALUABLE_FINDINGS for the same ledger and empty final inline comment set.

@shuke987

shuke987 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 90.00% (9/10) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29123 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 2ca7ced274ca3bd29bbe275c3cd39e1f1e6b5080, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17611	3996	4041	3996
q2	2450	318	197	197
q3	10267	1384	812	812
q4	4687	479	345	345
q5	7668	856	556	556
q6	202	170	135	135
q7	750	822	612	612
q8	9879	1440	1486	1440
q9	6043	4328	4337	4328
q10	6853	1772	1500	1500
q11	493	333	319	319
q12	725	547	425	425
q13	18131	3352	2734	2734
q14	268	257	250	250
q15	q16	785	781	708	708
q17	978	949	881	881
q18	7024	5827	5539	5539
q19	1695	1285	1098	1098
q20	725	637	533	533
q21	5766	2589	2425	2425
q22	420	354	290	290
Total cold run time: 103420 ms
Total hot run time: 29123 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4405	4374	4237	4237
q2	284	316	214	214
q3	4558	4929	4459	4459
q4	2037	2148	1374	1374
q5	4434	4339	4291	4291
q6	222	176	127	127
q7	1747	2060	1696	1696
q8	2510	2123	2102	2102
q9	7890	7962	7778	7778
q10	4789	4702	4324	4324
q11	575	429	382	382
q12	739	751	532	532
q13	3363	3600	3053	3053
q14	296	311	301	301
q15	q16	721	757	677	677
q17	1326	1323	1293	1293
q18	7909	7417	6960	6960
q19	1061	1060	1064	1060
q20	2220	2213	1934	1934
q21	5203	4542	4382	4382
q22	505	442	400	400
Total cold run time: 56794 ms
Total hot run time: 51576 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 180399 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 2ca7ced274ca3bd29bbe275c3cd39e1f1e6b5080, data reload: false

query5	4311	633	488	488
query6	464	236	226	226
query7	4862	590	336	336
query8	337	186	173	173
query9	8762	4045	3998	3998
query10	498	347	274	274
query11	5922	2362	2145	2145
query12	168	107	98	98
query13	1251	627	449	449
query14	6283	5326	4969	4969
query14_1	4281	4308	4325	4308
query15	215	208	183	183
query16	1029	493	471	471
query17	1164	730	604	604
query18	2524	472	355	355
query19	223	200	160	160
query20	116	108	110	108
query21	240	161	136	136
query22	13663	13613	13355	13355
query23	17353	16563	16180	16180
query23_1	16331	16284	16287	16284
query24	7595	1779	1313	1313
query24_1	1328	1309	1311	1309
query25	578	463	405	405
query26	1327	363	207	207
query27	2572	627	381	381
query28	4463	2022	1973	1973
query29	1073	605	468	468
query30	335	269	215	215
query31	1109	1106	1003	1003
query32	111	61	58	58
query33	524	333	251	251
query34	1177	1164	658	658
query35	798	797	676	676
query36	1429	1419	1327	1327
query37	151	110	89	89
query38	1914	1739	1701	1701
query39	942	957	937	937
query39_1	885	916	906	906
query40	245	166	141	141
query41	71	63	62	62
query42	95	91	97	91
query43	328	331	290	290
query44	1446	820	793	793
query45	202	195	185	185
query46	1082	1195	776	776
query47	2394	2380	2329	2329
query48	396	415	302	302
query49	591	457	321	321
query50	1083	429	337	337
query51	10909	10667	10593	10593
query52	86	91	75	75
query53	258	286	203	203
query54	275	266	215	215
query55	72	71	65	65
query56	287	283	290	283
query57	1435	1393	1288	1288
query58	283	250	232	232
query59	1604	1647	1439	1439
query60	302	272	252	252
query61	149	172	146	146
query62	683	633	585	585
query63	240	197	207	197
query64	2814	1027	828	828
query65	4860	4794	4771	4771
query66	1829	512	387	387
query67	29689	29520	29489	29489
query68	3115	1468	1018	1018
query69	408	298	258	258
query70	1095	959	969	959
query71	386	319	312	312
query72	3043	2772	2406	2406
query73	882	768	450	450
query74	5084	4998	4742	4742
query75	2617	2580	2250	2250
query76	2371	1182	783	783
query77	355	375	287	287
query78	12315	12363	11764	11764
query79	1413	1123	765	765
query80	658	533	457	457
query81	475	325	276	276
query82	571	160	126	126
query83	395	323	287	287
query84	268	158	127	127
query85	939	596	495	495
query86	356	292	281	281
query87	1837	1825	1784	1784
query88	3693	2792	2763	2763
query89	456	403	360	360
query90	1903	196	200	196
query91	196	187	160	160
query92	66	60	57	57
query93	1574	1645	971	971
query94	556	341	320	320
query95	768	476	461	461
query96	990	789	340	340
query97	2689	2727	2571	2571
query98	218	216	203	203
query99	1130	1169	1037	1037
Total cold run time: 265299 ms
Total hot run time: 180399 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.94 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 2ca7ced274ca3bd29bbe275c3cd39e1f1e6b5080, data reload: false

query1	0.01	0.01	0.00
query2	0.10	0.05	0.04
query3	0.26	0.13	0.13
query4	1.61	0.14	0.13
query5	0.24	0.23	0.21
query6	1.29	1.04	1.06
query7	0.04	0.00	0.00
query8	0.05	0.04	0.03
query9	0.39	0.32	0.32
query10	0.55	0.54	0.60
query11	0.20	0.14	0.14
query12	0.19	0.15	0.14
query13	0.48	0.47	0.48
query14	1.02	1.01	1.02
query15	0.60	0.59	0.59
query16	0.29	0.33	0.33
query17	1.10	1.07	1.08
query18	0.22	0.21	0.22
query19	2.04	1.98	1.93
query20	0.01	0.01	0.01
query21	15.44	0.23	0.14
query22	4.79	0.05	0.05
query23	16.13	0.30	0.12
query24	3.02	0.40	0.33
query25	0.11	0.05	0.04
query26	0.74	0.20	0.15
query27	0.06	0.03	0.04
query28	3.49	0.93	0.54
query29	12.47	4.13	3.22
query30	0.27	0.16	0.16
query31	2.78	0.60	0.32
query32	3.22	0.59	0.49
query33	3.12	3.18	3.16
query34	15.49	4.26	3.53
query35	3.52	3.49	3.56
query36	0.56	0.45	0.44
query37	0.08	0.07	0.06
query38	0.06	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.17	0.16
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.42 s
Total hot run time: 24.94 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 13.46% (7/52) 🎉
Increment coverage report
Complete coverage report

@starocean999
starocean999 merged commit cbccdaf into apache:master Jul 9, 2026
33 checks passed
hello-stephen pushed a commit that referenced this pull request Jul 17, 2026
Related PR: #65205

Problem Summary:

PR #65205 introduced a correctness issue in leading hint planning by
changing how semi/anti join constraints are matched. This PR reverts
merge commit `cbccdafa41adfff73e683ac1dfcae46638c16d48` in full,
restoring the previous planner behavior while a correct fix is prepared.
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.

3 participants