Skip to content

[fix](fe) Preserve required slots in TopN lazy materialization#65530

Open
morrySnow wants to merge 1 commit into
apache:masterfrom
morrySnow:fix-lazy
Open

[fix](fe) Preserve required slots in TopN lazy materialization#65530
morrySnow wants to merge 1 commit into
apache:masterfrom
morrySnow:fix-lazy

Conversation

@morrySnow

@morrySnow morrySnow commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: #51329

Problem Summary: TopN lazy materialization could produce invalid plans in two slot-pruning cases: an output alias was selected as lazy while its base slot remained an eager sorting output, or an eager sorting slot used by a Filter was removed together with lazy predicate slots. Keep aliases eager when their base is eager, and remove only selected lazy slots from Filter outputs.

Release note

Fix invalid plans caused by pruning slots still required by TopN lazy materialization.

Check List (For Author)

  • Test: Unit Test and Regression Test
    • LazyMaterializeTopNTest
    • LazySlotPruningTest
    • query_p0/topn_lazy/topn_lazy_on_data_model
    • query_p0/topn_lazy/usingIndex/topNLazyMaterializationUsingIndex
  • Behavior changed: Yes (slots required by TopN ordering remain eagerly materialized)
  • Does this need documentation: No

### What problem does this PR solve?

Issue Number: None

Related PR: apache#51329

Problem Summary: TopN lazy materialization could produce invalid plans in two slot-pruning cases: an output alias was selected as lazy while its base slot remained an eager sorting output, or an eager sorting slot used by a Filter was removed together with lazy predicate slots. Keep aliases eager when their base is eager, and remove only selected lazy slots from Filter outputs.

### Release note

Fix invalid plans caused by pruning slots still required by TopN lazy materialization.

### Check List (For Author)

- Test: Unit Test and Regression Test
    - LazyMaterializeTopNTest
    - LazySlotPruningTest
    - query_p0/topn_lazy/topn_lazy_on_data_model
    - query_p0/topn_lazy/usingIndex/topNLazyMaterializationUsingIndex
- Behavior changed: Yes (slots required by TopN ordering remain eagerly materialized)
- Does this need documentation: No
@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?

@morrySnow

Copy link
Copy Markdown
Contributor Author

/review

@morrySnow

Copy link
Copy Markdown
Contributor 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.

I found two remaining issues in the TopN lazy materialization changes. The direct order-key pruning case is improved and the added tests are deterministic, but there are still unhandled slot-retention cases that can either produce an invalid plan or carry unnecessary materialized columns through TopN.

Checkpoint summary: the task goal is clear, but not fully accomplished for alias-vs-alias sharing and predicate-only filter slots; the patch is focused; no concurrency, lifecycle, persistence, config, FE/BE protocol, or cloud/transaction behavior is involved; the relevant parallel paths are the project alias and using-index filter pruning paths; test coverage was checked and should be extended for the alias-vs-alias case. I did not run builds or tests because this review environment is review-only.

Set<Slot> requiredMaterializedSlots, Set<Slot> materializedSlots) {
List<Slot> requiredOutputSlots = new ArrayList<>();
for (Map.Entry<Slot, MaterializeSource> entry : materializeMap.entrySet()) {
if (requiredMaterializedSlots.contains(entry.getKey())

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 misses the case where the eager output sharing the same base column is itself another alias. A reduced shape is:

TopN(order by a)
  Project(username AS a, username AS b)
    Scan(username)

a is materialized because it is the TopN order key, but materializedSlots contains alias slot a, not the scan base slot username. For b, MaterializeProbeVisitor traces to MaterializeSource.baseSlot = username, and this check compares that base only with materializedSlots.contains(username), so b stays lazy. LazySlotPruning then maps lazy b to child slot username and removes it from the scan while keeping alias a, leaving Project(username AS a) above a child that no longer outputs username.

Please protect base slots referenced by retained simple aliases as well, and add a regression such as SELECT username AS a, username AS b FROM mow ORDER BY a LIMIT 5.

.copyStatsAndGroupIdFrom(filter).resetLogicalProperties();
List<Slot> filterOutput = Lists.newArrayList(filter.getOutput());
filterOutput.removeAll(filter.getInputSlots());
// Predicate slots that are not lazy can still be required by TopN order keys.

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 projection now keeps every non-lazy Filter input above the Filter. In the using-index path, some predicate slots still have to be read eagerly to evaluate the Filter, but they are not necessarily needed by TopN or the final output.

Project(v, pad)
  TopN(order by k1)
    Filter(v IS NULL AND x > 0)
      Scan(k1, v, pad, x)

Here v can be lazy and triggers this branch, k1 must stay for ordering, but x is predicate-only. Since filter.getOutput() is the child output, subtracting only context.lazySlots leaves [k1, x, row_id], so x is carried through TopN and PhysicalLazyMaterialize as materialized tuple data even though it should be dropped after the Filter. The fix should project the slots required above the Filter, for example order/materialized outputs plus row id, rather than all non-lazy Filter inputs.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17681	4170	4125	4125
q2	2033	326	200	200
q3	10308	1447	817	817
q4	4681	466	341	341
q5	7540	833	584	584
q6	180	164	135	135
q7	768	844	626	626
q8	9318	1577	1486	1486
q9	5682	4379	4364	4364
q10	6804	1763	1549	1549
q11	509	338	323	323
q12	682	541	423	423
q13	18122	3513	2738	2738
q14	283	259	242	242
q15	q16	786	792	706	706
q17	1011	1000	923	923
q18	6964	5744	5706	5706
q19	1166	1273	1046	1046
q20	747	659	513	513
q21	5654	2602	2330	2330
q22	423	354	298	298
Total cold run time: 101342 ms
Total hot run time: 29475 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4464	4368	4383	4368
q2	307	333	211	211
q3	4607	4997	4423	4423
q4	2058	2153	1389	1389
q5	4481	4329	4287	4287
q6	225	179	127	127
q7	1708	1941	1847	1847
q8	2587	2184	2189	2184
q9	8130	8244	7738	7738
q10	4730	4725	4283	4283
q11	572	428	393	393
q12	773	750	538	538
q13	3310	3592	2920	2920
q14	296	296	276	276
q15	q16	756	747	643	643
q17	1363	1326	1362	1326
q18	7970	7572	7388	7388
q19	1148	1087	1043	1043
q20	2214	2214	1931	1931
q21	5328	4674	4468	4468
q22	519	449	408	408
Total cold run time: 57546 ms
Total hot run time: 52191 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 180487 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 f29e4beebc8545d24f979bc49e9ac94296b4a050, data reload: false

query5	4328	618	498	498
query6	450	220	198	198
query7	4854	616	350	350
query8	332	196	173	173
query9	8772	4073	4103	4073
query10	449	361	327	327
query11	5898	2343	2155	2155
query12	163	105	102	102
query13	1258	636	470	470
query14	6195	5338	4985	4985
query14_1	4348	4288	4289	4288
query15	221	212	182	182
query16	1012	479	452	452
query17	952	723	596	596
query18	2518	483	361	361
query19	215	196	150	150
query20	113	112	109	109
query21	235	155	134	134
query22	13710	13663	13347	13347
query23	17460	16590	16246	16246
query23_1	16350	16328	16285	16285
query24	7538	1786	1292	1292
query24_1	1347	1305	1304	1304
query25	568	473	399	399
query26	1351	345	214	214
query27	2598	584	394	394
query28	4449	2043	2022	2022
query29	1099	636	502	502
query30	338	278	229	229
query31	1118	1089	984	984
query32	113	64	61	61
query33	535	334	265	265
query34	1219	1126	639	639
query35	759	782	677	677
query36	1406	1410	1195	1195
query37	153	107	93	93
query38	1927	1696	1644	1644
query39	925	919	898	898
query39_1	871	864	895	864
query40	240	164	141	141
query41	70	65	64	64
query42	98	92	90	90
query43	334	330	289	289
query44	1480	790	771	771
query45	194	192	184	184
query46	1027	1248	740	740
query47	2385	2326	2245	2245
query48	403	390	291	291
query49	591	417	316	316
query50	1064	419	334	334
query51	10604	10767	10625	10625
query52	88	88	75	75
query53	277	280	200	200
query54	281	231	211	211
query55	75	71	65	65
query56	293	301	286	286
query57	1439	1409	1327	1327
query58	284	247	249	247
query59	1571	1644	1474	1474
query60	314	266	255	255
query61	154	142	160	142
query62	698	665	580	580
query63	242	203	211	203
query64	2831	1057	876	876
query65	4887	4815	4771	4771
query66	1811	502	377	377
query67	29543	29440	29379	29379
query68	3131	1573	1043	1043
query69	418	289	266	266
query70	1049	991	942	942
query71	349	313	298	298
query72	3340	2765	2388	2388
query73	849	749	436	436
query74	5108	4965	4750	4750
query75	2610	2581	2229	2229
query76	2342	1178	775	775
query77	338	374	287	287
query78	12320	12261	11795	11795
query79	1423	1180	762	762
query80	738	550	485	485
query81	472	314	274	274
query82	572	158	121	121
query83	394	319	288	288
query84	327	165	132	132
query85	976	604	508	508
query86	418	299	286	286
query87	1839	1819	1733	1733
query88	3741	2803	2791	2791
query89	447	401	348	348
query90	1803	204	203	203
query91	200	191	169	169
query92	65	64	57	57
query93	1482	1594	1095	1095
query94	626	360	295	295
query95	779	497	560	497
query96	1099	790	362	362
query97	2675	2699	2565	2565
query98	221	211	204	204
query99	1146	1174	1037	1037
Total cold run time: 265160 ms
Total hot run time: 180487 ms

@hello-stephen

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

query1	0.00	0.01	0.00
query2	0.09	0.04	0.05
query3	0.25	0.14	0.14
query4	1.61	0.15	0.14
query5	0.28	0.22	0.22
query6	1.28	1.10	1.06
query7	0.04	0.01	0.01
query8	0.06	0.04	0.03
query9	0.40	0.32	0.31
query10	0.57	0.56	0.57
query11	0.20	0.15	0.14
query12	0.19	0.16	0.15
query13	0.47	0.48	0.48
query14	1.01	1.03	1.02
query15	0.62	0.58	0.59
query16	0.32	0.32	0.33
query17	1.10	1.09	1.13
query18	0.22	0.20	0.21
query19	2.02	1.99	1.99
query20	0.01	0.01	0.01
query21	15.44	0.22	0.15
query22	4.75	0.05	0.05
query23	16.13	0.32	0.13
query24	2.98	0.44	0.31
query25	0.12	0.06	0.04
query26	0.73	0.19	0.14
query27	0.05	0.03	0.03
query28	3.52	0.92	0.54
query29	12.46	4.09	3.30
query30	0.28	0.16	0.16
query31	2.77	0.58	0.32
query32	3.23	0.58	0.48
query33	3.16	3.17	3.18
query34	15.49	4.24	3.55
query35	3.56	3.55	3.59
query36	0.56	0.44	0.44
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.17	0.15	0.15
query41	0.08	0.04	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 96.48 s
Total hot run time: 25.22 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 76.92% (10/13) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 12.36% (11/89) 🎉
Increment coverage report
Complete coverage report

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants