Skip to content

[fix](mtmv) Clear stale partition state for prepared statements - #66370

Open
seawinde wants to merge 3 commits into
apache:masterfrom
seawinde:fix-prepared-statement-partition-state
Open

[fix](mtmv) Clear stale partition state for prepared statements#66370
seawinde wants to merge 3 commits into
apache:masterfrom
seawinde:fix-prepared-statement-partition-state

Conversation

@seawinde

@seawinde seawinde commented Aug 3, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: N/A

Related PR: #49514, #58643

Problem Summary:
Repeated server prepared statement executions can retain query partition and
relation mappings from earlier executions. No GitHub issue is associated with
this fix; the production incident is tracked outside GitHub.

Root cause: In ExecuteCommand.run(), server prepared statements reuse the
same StatementContext, while QueryPartitionCollector appends current
partition and relation mappings without removing mappings from prior
executions. PartitionCompensator.getQueryUsedPartitions() then scans the
accumulated entries and creates a temporary BitSet for every RelationId,
increasing FE CPU, allocation, and GC overhead as the connection remains active.

Change Summary:

File Change Description
ExecuteCommand.java Clear the previous execution's query partition and relation mappings before planning the next EXECUTE.
PartitionCompensator.java Query the existing relation BitSet directly instead of allocating a singleton BitSet for each mapping.
ExecuteCommandTest.java Verify prior mappings are cleared before planning and only current execution mappings remain.

The change resets only the two confirmed per-execution mappings and leaves
placeholder, short-circuit, connector, MVCC, and other prepared statement state
unchanged.

flowchart LR
    A[EXECUTE starts] --> B[Clear prior partition mappings]
    B --> C[Plan current execution]
    C --> D[Check RelationId with BitSet.get]
Loading

Release note

Fixed excessive FE CPU and memory usage when repeatedly executing prepared
statements with materialized view rewrite.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • 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.trees.plans.commands.ExecuteCommandTest,org.apache.doris.nereids.rules.exploration.mv.PartitionCompensatorTest

  • 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

### What problem does this PR solve?

Issue Number: N/A

Related PR: N/A

Problem Summary: Server prepared statements reuse a StatementContext
across executions. Query partition and relation mappings from prior
executions therefore accumulate, while partition compensation allocates
a temporary BitSet for each stored RelationId. Clear the per-execution
mappings before planning each EXECUTE and query the existing BitSet
directly.

### Release note

Fixed excessive FE CPU and memory usage when repeatedly executing
prepared statements with materialized view rewrite.

### Check List (For Author)

- Test: Unit Test
    - ExecuteCommandTest
    - PartitionCompensatorTest
- Behavior changed: No
- 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?

@seawinde

seawinde commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

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

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 20.00% (3/15) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17615	3894	3901	3894
q2	2030	320	200	200
q3	10260	1350	793	793
q4	4685	470	341	341
q5	7514	813	548	548
q6	178	168	141	141
q7	734	800	602	602
q8	9663	1500	1548	1500
q9	5719	3979	3956	3956
q10	6811	1620	1339	1339
q11	506	365	325	325
q12	762	574	454	454
q13	18125	3181	2684	2684
q14	258	267	240	240
q15	q16	738	727	653	653
q17	952	961	960	960
q18	6822	5629	5465	5465
q19	1455	1264	1062	1062
q20	813	675	574	574
q21	5770	2548	2343	2343
q22	429	360	304	304
Total cold run time: 101839 ms
Total hot run time: 28378 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4216	4124	4117	4117
q2	286	307	208	208
q3	4542	4887	4391	4391
q4	2128	2230	1409	1409
q5	4156	4065	4064	4064
q6	228	170	124	124
q7	1668	1568	1417	1417
q8	2412	2150	2052	2052
q9	7266	7094	7160	7094
q10	4297	4238	3880	3880
q11	543	398	360	360
q12	704	725	508	508
q13	3234	3529	2958	2958
q14	302	299	267	267
q15	q16	692	729	627	627
q17	1284	1247	1264	1247
q18	7920	7318	7121	7121
q19	1072	1089	1040	1040
q20	2186	2177	1918	1918
q21	5194	4519	4379	4379
q22	521	467	398	398
Total cold run time: 54851 ms
Total hot run time: 49579 ms

### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#49514, apache#58643

Problem Summary: The existing unit test only checked stale partition
mappings after the mocked executor returned, so it could not distinguish
cleanup before planning from cleanup after execution. Add a focused test
that simulates current planning state being written during each EXECUTE
and verifies that only the current RelationId remains.

### Release note

None

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.nereids.trees.plans.commands.ExecuteCommandTest
- Behavior changed: No
- Does this need documentation: No
@seawinde

seawinde commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

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

query5	4333	613	457	457
query6	473	229	210	210
query7	4836	547	329	329
query8	328	192	165	165
query9	8788	4005	3991	3991
query10	461	336	314	314
query11	5816	2180	2033	2033
query12	156	99	97	97
query13	1268	612	432	432
query14	6200	4658	4356	4356
query14_1	3752	3796	3778	3778
query15	212	205	172	172
query16	1027	486	459	459
query17	1137	679	548	548
query18	2451	471	348	348
query19	215	198	150	150
query20	106	104	103	103
query21	234	158	134	134
query22	12957	12948	12719	12719
query23	17276	16422	15937	15937
query23_1	16063	16081	16094	16081
query24	7597	1667	1241	1241
query24_1	1266	1206	1241	1206
query25	561	446	419	419
query26	1379	345	210	210
query27	2675	546	384	384
query28	4455	2058	2023	2023
query29	1067	589	458	458
query30	338	254	226	226
query31	1113	1057	940	940
query32	102	60	57	57
query33	514	297	236	236
query34	1171	1120	628	628
query35	757	741	640	640
query36	777	763	714	714
query37	143	106	101	101
query38	1825	1632	1605	1605
query39	812	830	816	816
query39_1	787	770	779	770
query40	254	161	143	143
query41	65	62	62	62
query42	92	92	90	90
query43	308	314	271	271
query44	1397	803	776	776
query45	186	173	159	159
query46	1069	1203	705	705
query47	1599	1588	1438	1438
query48	411	429	290	290
query49	610	411	288	288
query50	1097	426	342	342
query51	10456	10401	10592	10401
query52	84	85	74	74
query53	264	275	203	203
query54	270	245	221	221
query55	74	70	72	70
query56	296	292	273	273
query57	1043	1016	979	979
query58	292	254	268	254
query59	1511	1565	1337	1337
query60	313	281	259	259
query61	153	142	141	141
query62	388	326	269	269
query63	229	196	193	193
query64	2808	992	830	830
query65	3893	3827	3800	3800
query66	1853	462	362	362
query67	28160	28133	28040	28040
query68	3229	1449	1047	1047
query69	411	296	260	260
query70	883	802	777	777
query71	372	333	315	315
query72	3031	2834	2455	2455
query73	820	757	428	428
query74	4648	4495	4301	4301
query75	2372	2397	1996	1996
query76	2314	1110	731	731
query77	328	371	265	265
query78	11238	11069	10571	10571
query79	1388	1130	738	738
query80	1301	538	461	461
query81	545	310	286	286
query82	599	149	114	114
query83	360	313	301	301
query84	278	163	132	132
query85	966	602	519	519
query86	406	229	223	223
query87	1796	1795	1712	1712
query88	3821	2827	2832	2827
query89	393	315	283	283
query90	1886	197	187	187
query91	201	187	161	161
query92	64	58	57	57
query93	1726	1485	1011	1011
query94	719	339	299	299
query95	775	509	590	509
query96	1069	805	357	357
query97	2449	2455	2349	2349
query98	207	208	192	192
query99	720	728	615	615
Total cold run time: 256088 ms
Total hot run time: 168879 ms

@hello-stephen

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

query1	0.00	0.00	0.00
query2	0.09	0.05	0.05
query3	0.25	0.14	0.13
query4	1.61	0.14	0.14
query5	0.24	0.24	0.22
query6	1.16	0.82	0.82
query7	0.04	0.00	0.00
query8	0.05	0.04	0.04
query9	0.38	0.31	0.31
query10	0.56	0.52	0.53
query11	0.19	0.13	0.14
query12	0.18	0.14	0.14
query13	0.46	0.45	0.46
query14	0.99	0.98	0.99
query15	0.59	0.57	0.58
query16	0.32	0.33	0.32
query17	1.08	1.09	1.09
query18	0.22	0.21	0.20
query19	2.08	1.98	1.99
query20	0.02	0.01	0.01
query21	15.42	0.22	0.13
query22	4.79	0.05	0.05
query23	16.13	0.32	0.12
query24	3.01	0.43	0.32
query25	0.10	0.06	0.04
query26	0.74	0.20	0.15
query27	0.03	0.04	0.04
query28	3.53	0.75	0.34
query29	12.54	4.08	3.20
query30	0.27	0.16	0.16
query31	2.77	0.55	0.31
query32	3.22	0.58	0.50
query33	3.09	3.20	3.26
query34	15.51	3.97	3.27
query35	3.23	3.19	3.21
query36	0.54	0.44	0.41
query37	0.08	0.07	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.18	0.15	0.14
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: 95.94 s
Total hot run time: 23.89 s

@seawinde
seawinde marked this pull request as ready for review August 3, 2026 09:49
@seawinde seawinde changed the title [fix](fe) Clear stale partition state for prepared statements [fix](mtmv) Clear stale partition state for prepared statements Aug 3, 2026
@924060929

Copy link
Copy Markdown
Contributor

/review

924060929
924060929 previously approved these changes Aug 3, 2026
@github-actions github-actions Bot added the approved Indicates a PR has been approved by one committer. label Aug 3, 2026
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

PR approved by anyone and no changes requested.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

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

@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 three issues in the reused StatementContext reset: one can return stale MV rows, while the others retain stale planning/configuration state and growing optimizer work.

Critical checkpoint conclusions:

  • Goal and data correctness: the allocation-free BitSet.get rewrite is correct, and the two new clears fix their narrow maps, but the prepared-execution reset remains incomplete. A stale valid-partition cache can omit required union compensation and return stale MV rows. Retained full-plan and phase state also defeats the stated repeated-EXECUTE resource/behavior goal.
  • Scope and design: the patch is small and readable, but adding individual clears at the command boundary is not sufficiently complete for a context that deliberately survives executions; a centralized per-external-EXECUTE reset is needed.
  • Concurrency and lifecycle: no new lock or concurrency issue was found; commands on one connection are serialized. The important lifecycle is normal prepared-context reuse. Reusable short-circuit and group-commit branches do not consume this MV state, while the non-reusable short-circuit refresh installs a fresh context.
  • Configuration and compatibility: no FE/BE protocol, function symbol, storage-format, persistence, or rolling-upgrade change is introduced. Dynamic MV strategy/hint behavior and disable_nereids_rules changes are affected by the retained state described inline.
  • Parallel paths and conditions: normal, reusable/refreshed short-circuit, group-commit, exception, ALL_PARTITIONS, empty-filter, and relation-filter paths were reviewed. The direct membership condition is equivalent to the removed singleton-BitSet intersection.
  • Tests and results: the new Mockito test proves only that the two selected maps are cleared. Existing PartitionCompensatorTest cases cover the local BitSet/sentinel behavior, but no test performs a second real planning pass with changed MV validity or retained planner state, so it misses the correctness failure and other lifecycle defects. Per the review workflow, no local build or test was run.
  • Observability, transactions, and performance: no transaction/persistence or FE-BE variable path is involved. The direct BitSet lookup removes avoidable allocation, but retained plans, filters, rewrite duration, cached rules, and statistics still cause incorrect accounting or growing work/memory.

There was no additional user-provided review focus. The full PR was reviewed.

}
PrepareCommand prepareCommand = preparedStmtCtx.command;
StatementContext statementContext = preparedStmtCtx.getStatementContext();
// Prepared statements reuse StatementContext across executions. Discard partition

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.

[P2] Reset the remaining per-query planner state here

These two clears leave other state from the same planning pass alive in the reused context: materializedViewRewriteDuration accumulates until later EXECUTEs hit the rewrite cutoff; hints appends until one USE_MV/NO_USE_MV becomes a duplicate; joinFilters grows and is rescanned by CostModel; and queryStatsRecorded suppresses hit accounting after the first client execution. The cached disableRules BitSet also makes a later SET disable_nereids_rules ineffective for this prepared statement. Please make this a centralized per-external-EXECUTE reset (without resetting retry-scoped state inside one execution) and exercise an actual second planner run rather than only a mocked executor.execute().

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed the MV-related part in b959429. StatementContext.resetMaterializedViewStateForPreparedExecution() is called once at the external EXECUTE boundary, resets materializedViewRewriteDuration, and removes stale UseMvHint instances while preserving unrelated hints. The test now invokes a real NereidsPlanner.plan() on both EXECUTEs.

I intentionally did not clear joinFilters, disableRules, or queryStatsRecorded in this PR. They are independent prepared-StatementContext lifecycle concerns, not involved in the partition/MV root cause, and resetting them would change join-cost, session-rule, and query-statistics behavior without dedicated coverage. They should be handled separately rather than broadening this correctness fix.

StatementContext statementContext = preparedStmtCtx.getStatementContext();
// Prepared statements reuse StatementContext across executions. Discard partition
// information collected by the previous execution before planning the current one.
statementContext.getTableUsedPartitionNameMap().clear();

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.

[P1] Reset cached MV-valid partitions before each EXECUTE

On the CBO/NOT_IN_RBO path, this reused context also retains mvCanRewritePartitionsMap. Suppose EXECUTE 1 records {m1,m2} as synchronized, then a write makes only m2 stale. EXECUTE 2 recomputes current validity as {m1}, which is still nonempty, but MTMVRelationManager.isMVPartitionValid uses putIfAbsent, so PartitionCompensator.calcInvalidPartitions reads the old {m1,m2}. It consequently adds neither PartitionRemover nor the base-table LogicalUnion for m2, and stale MV rows can be returned. Clear this cache at the same per-execution boundary and cover a two-EXECUTE partial-invalidation case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in b959429. mvCanRewritePartitionsMap is now cleared at the same per-external-EXECUTE boundary as the query partition mappings, so the next planning pass cannot read the prior {m1,m2} value through putIfAbsent and must recompute the current valid set.

The repeated-execution test seeds a stale MV-valid-partition cache, verifies it is empty before each planning pass, and runs the real Nereids planner twice. This directly covers the cache boundary responsible for the partial-invalidation failure without adding a heavyweight MTMV integration setup.

// Prepared statements reuse StatementContext across executions. Discard partition
// information collected by the previous execution before planning the current one.
statementContext.getTableUsedPartitionNameMap().clear();
statementContext.getCommonTableIdToRelationIdMap().clear();

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.

[P2] Reset retained MV pre-rewrite state for each EXECUTE

RecordPlanForMvPreRewrite appends a complete analyzed plan on every eligible execution, but this boundary never clears tmpPlanForMvRewrite. preMaterializedViewRewrite then walks the entire retained history on each later pass (the code even assumes the list has only one plan), while the retained preMvRewritten flag makes OptimizeGroupExpressionJob omit all MV exploration rules from the subsequent CBO phase. Repeated EXECUTEs therefore retain unbounded plan graphs and do O(n) historical work per pass while carrying the prior phase decision forward. Clear the temporary/rewritten plans, MV phase flags/masks, and relation statistics here, and add a repeated real-planning test that keeps the state bounded and validates the next execution's MV phases independently.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in b959429. The per-external-EXECUTE reset now clears tmpPlanForMvRewrite, rewrittenPlansByMv, needPreMvRewriteRuleMasks, needPreMvRewrite, preMvRewritten, materializationRewrittenSuccessSet, and relationIdToStatisticsMap, together with the MV partition caches, rewrite duration, and stale UseMvHint entries.

The test executes a real Nereids planning pass twice on the reused prepared StatementContext; before each pass it verifies the previous MV plans, masks, flags, successes, and relation statistics are gone, then repopulates the prior-execution state to validate the second boundary independently and keep retained plan state bounded.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17602	3941	3888	3888
q2	2045	320	215	215
q3	10228	1344	805	805
q4	4698	467	334	334
q5	7595	831	540	540
q6	187	163	132	132
q7	747	810	602	602
q8	10044	1477	1567	1477
q9	5640	4013	4007	4007
q10	6774	1620	1348	1348
q11	500	345	312	312
q12	775	561	441	441
q13	18113	3258	2695	2695
q14	266	252	237	237
q15	q16	729	716	654	654
q17	1137	1021	846	846
q18	6736	5664	5624	5624
q19	1338	1273	1035	1035
q20	789	673	556	556
q21	5607	2566	2356	2356
q22	431	359	300	300
Total cold run time: 101981 ms
Total hot run time: 28404 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4233	4133	4143	4133
q2	285	315	228	228
q3	4537	4912	4429	4429
q4	2161	2236	1402	1402
q5	4183	4064	4067	4064
q6	221	168	126	126
q7	1691	1571	1386	1386
q8	2640	2273	2023	2023
q9	7264	7142	7231	7142
q10	4318	4261	3845	3845
q11	549	395	363	363
q12	723	765	494	494
q13	3166	3531	2888	2888
q14	297	296	279	279
q15	q16	690	704	619	619
q17	1286	1300	1297	1297
q18	7830	7191	7197	7191
q19	1048	1047	1012	1012
q20	2191	2173	1913	1913
q21	5211	4562	4449	4449
q22	502	440	407	407
Total cold run time: 55026 ms
Total hot run time: 49690 ms

@hello-stephen

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

query5	4365	619	462	462
query6	454	223	206	206
query7	4872	592	335	335
query8	328	182	176	176
query9	8769	4099	4024	4024
query10	485	396	305	305
query11	5860	2182	1999	1999
query12	158	97	95	95
query13	1292	572	427	427
query14	6347	4662	4310	4310
query14_1	3747	3746	3758	3746
query15	210	197	173	173
query16	1030	455	450	450
query17	1127	669	524	524
query18	2697	470	337	337
query19	200	188	144	144
query20	107	100	100	100
query21	241	152	135	135
query22	12965	13020	12809	12809
query23	17241	16392	16027	16027
query23_1	16067	16164	16066	16066
query24	7552	1702	1236	1236
query24_1	1276	1257	1226	1226
query25	558	444	390	390
query26	1352	353	226	226
query27	2549	622	381	381
query28	4470	2058	2033	2033
query29	1066	635	457	457
query30	337	258	227	227
query31	1110	1072	949	949
query32	109	62	58	58
query33	509	306	233	233
query34	1167	1130	622	622
query35	728	738	635	635
query36	779	781	700	700
query37	156	101	90	90
query38	1834	1656	1604	1604
query39	825	799	777	777
query39_1	805	759	808	759
query40	254	175	147	147
query41	65	63	64	63
query42	90	89	91	89
query43	313	318	276	276
query44	1422	794	762	762
query45	186	179	169	169
query46	1081	1239	759	759
query47	1610	1688	1526	1526
query48	414	393	316	316
query49	582	406	289	289
query50	1181	444	338	338
query51	10537	10494	10588	10494
query52	84	85	80	80
query53	260	278	200	200
query54	283	221	225	221
query55	74	77	70	70
query56	290	289	297	289
query57	1031	1021	928	928
query58	278	240	246	240
query59	1502	1582	1373	1373
query60	316	270	250	250
query61	146	141	146	141
query62	400	322	290	290
query63	236	193	188	188
query64	2779	1029	864	864
query65	3893	3819	3833	3819
query66	1781	463	357	357
query67	28113	28211	27911	27911
query68	3178	1640	1018	1018
query69	409	299	266	266
query70	886	794	786	786
query71	388	342	306	306
query72	2990	2817	2538	2538
query73	883	779	450	450
query74	4630	4512	4281	4281
query75	2392	2361	2004	2004
query76	2330	1117	754	754
query77	344	403	289	289
query78	11086	11108	10549	10549
query79	1398	1187	779	779
query80	1173	567	472	472
query81	507	326	283	283
query82	613	152	116	116
query83	411	331	311	311
query84	283	171	189	171
query85	958	610	543	543
query86	382	231	223	223
query87	1797	1795	1742	1742
query88	3739	2828	2814	2814
query89	408	318	278	278
query90	1766	194	194	194
query91	200	193	163	163
query92	62	59	55	55
query93	1658	1510	1061	1061
query94	628	338	299	299
query95	777	612	475	475
query96	1114	791	364	364
query97	2426	2456	2353	2353
query98	199	204	189	189
query99	719	712	605	605
Total cold run time: 255675 ms
Total hot run time: 169380 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.10	0.05	0.05
query3	0.25	0.14	0.14
query4	1.61	0.14	0.15
query5	0.23	0.21	0.22
query6	1.16	0.80	0.81
query7	0.03	0.01	0.00
query8	0.05	0.04	0.04
query9	0.37	0.32	0.31
query10	0.56	0.53	0.53
query11	0.19	0.14	0.14
query12	0.19	0.14	0.15
query13	0.45	0.47	0.47
query14	1.00	0.98	1.03
query15	0.61	0.58	0.58
query16	0.33	0.31	0.31
query17	1.10	1.13	1.13
query18	0.22	0.20	0.20
query19	2.01	1.95	1.94
query20	0.03	0.02	0.01
query21	15.42	0.18	0.12
query22	4.94	0.05	0.05
query23	16.15	0.32	0.12
query24	2.94	0.41	0.29
query25	0.12	0.05	0.03
query26	0.73	0.20	0.14
query27	0.05	0.03	0.03
query28	3.49	0.83	0.36
query29	12.53	4.02	3.19
query30	0.27	0.14	0.15
query31	2.77	0.57	0.32
query32	3.22	0.59	0.49
query33	3.14	3.15	3.15
query34	15.56	3.92	3.31
query35	3.29	3.21	3.22
query36	0.55	0.43	0.42
query37	0.08	0.07	0.06
query38	0.06	0.03	0.03
query39	0.04	0.03	0.03
query40	0.17	0.16	0.14
query41	0.08	0.04	0.04
query42	0.03	0.02	0.03
query43	0.05	0.04	0.03
Total cold run time: 96.18 s
Total hot run time: 23.85 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 25.00% (3/12) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: N/A

Related PR: apache#66370

Problem Summary: Server prepared statements reuse one StatementContext across external EXECUTEs. Materialized-view partition caches, pre-rewrite plans, phase decisions, hints, timing, and MV relation statistics from an earlier execution could therefore affect later planning or grow without bound. Reset only the partition and materialized-view planning state at the external EXECUTE boundary while preserving unrelated prepared-statement state.

### Release note

Fixed stale materialized-view planning state across repeated prepared statement executions.

### Check List (For Author)

- Test: Unit Test
    - ./run-fe-ut.sh --run org.apache.doris.nereids.trees.plans.commands.ExecuteCommandTest
- Behavior changed: Yes (each prepared EXECUTE independently computes partition and materialized-view rewrite state)
- Does this need documentation: No
@github-actions github-actions Bot removed the approved Indicates a PR has been approved by one committer. label Aug 4, 2026
@seawinde

seawinde commented Aug 4, 2026

Copy link
Copy Markdown
Member Author

run buildall

@seawinde

seawinde commented Aug 4, 2026

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

Request changes.

The direct BitSet.get replacement is semantically equivalent on the planner's valid RelationId domain, and the new boundary correctly clears the listed partition/result/phase caches. Two prepared-StatementContext lifecycle gaps still leave the overall MV-state isolation incomplete: a dropped/replaced MTMV generation can remain selectable, and an enabled materialization hook can keep discovery and related-table locking active after rewrite is disabled.

Critical checkpoint conclusions:

  • Goal and proof: the PR addresses retained partition/MV planning state and removes a per-entry allocation. The added tests prove reset timing and invoke a physical planner twice, but select 1 plus manually seeded mocks does not exercise either remaining discovery lifecycle. Real two-EXECUTE DROP/replacement and enabled-to-disabled regressions are still needed.
  • Scope and clarity: ExecuteCommand calls the reset at the correct external execution boundary, and the PartitionCompensator change is small and clear. The reset itself is broader than the PR description yet remains incomplete because candidate, related-table, and materialization-hook state is omitted.
  • Concurrency and locking: prepared execution is connection-serial, and no new lock-order inversion or deadlock was found. However, retained related tables expand the second execution's read-lock set; with rewrite disabled, an unrelated MV/base-table writer can still cause the one-minute planner wait or failure described inline.
  • Lifecycle and error behavior: normal planning rebuilds the cleared fields; nested retries do not re-enter ExecuteCommand, and reusable/stale short-circuit and group-commit paths do not consume the cleared MV state. Catalog DROP only marks/unregisters the old MTMV object; no downstream availability, lock, cache, scan-generation, or translation fence rejects that retained generation, which is the P1 issue below. Errors otherwise remain fail-fast.
  • Configuration and parallel paths: both query and DML materialization hooks eventually recheck their current enable flags, so no disabled rewrite is alleged. That check occurs after candidate discovery and table locking, leaving the P2 overhead/availability defect. Query, DML, RBO/CBO, short-circuit, group-commit, and retry paths were reviewed.
  • Compatibility, persistence, writes, and protocols: no FE-BE variable, serialization/storage format, EditLog, transaction, data-write, dynamic-config definition, or rolling-upgrade surface is changed.
  • Tests and results: the JUnit additions are synchronous and deterministic; existing partition tests cover empty masks, relation filters, concrete-empty sets, and ALL_PARTITIONS sentinels. This review remained static-only because the review contract forbids builds and test execution.
  • Performance and observability: the direct bit lookup removes the intended temporary allocation, and clearing retained plan/result state reduces repeated work. Retained candidates/hooks still undermine the CPU, memory, and lock-footprint goal. Existing planner logging is sufficient; no new metric or log is required for this cleanup.
  • User focus: review_focus.txt contains no additional guidance, so the complete PR was reviewed without a narrower focus.

Existing live threads were treated as known context and not repeated. After main-agent adjudication, a second full-coverage plus risk-focused round returned NO_NEW_VALUABLE_FINDINGS against the unchanged head and exact final comment set; all candidates are accepted, dismissed with evidence, or deduplicated.

needPreMvRewrite = false;
preMvRewritten = false;
materializationRewrittenSuccessSet.clear();
relationIdToStatisticsMap.clear();

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.

[P1] Clear retained MV candidates before rebuilding them

A dropped MTMV can still be selected on the next execution:

EXECUTE 1: ResultSink -> Scan(base)   candidateMTMVs={mv_old}
DROP MATERIALIZED VIEW mv_old
EXECUTE 2: ResultSink -> Scan(mv_old [dropped, old table id])

DROP marks the old object isDropped and removes it from the live relation manager, but this reset leaves candidateMTMVs/mtmvRelatedTables alive. getAvailableMTMVs then consumes the retained set directly and checks rewrite status/partitions, not isDropped or the current catalog generation; AsyncMaterializationContext can consequently generate a scan from that old object and partition IDs. Clear candidateMTMVs, candidateMVs, and mtmvRelatedTables here so collection rebuilds them, and cover DROP or same-name replacement between two real EXECUTEs.

commonTableIdToRelationIdToMap.clear();
mvCanRewritePartitionsMap.clear();
materializedViewRewriteDuration = 0;
hints.removeIf(UseMvHint.class::isInstance);

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.

[P2] Remove retained MV hooks when rewrite is disabled

An enabled execution installs InitMaterializationContextHook.INSTANCE in this reused context. If the session then disables MV rewrite, AddInitMaterializationHook merely declines to add another hook; it does not remove the old one. containMaterializedViewHook therefore remains true, so CollectRelation still discovers MVs and lock() still acquires all retained MV-related table locks before initMaterializationContext finally rechecks the disabled flag. A writer holding any such lock can make a base-table EXECUTE wait for the one-minute planner timeout or fail even though MV rewrite is off. Remove only materialization hook instances here (preserving unrelated hooks) and clear their candidate/related-table state so the current collect pass can re-add them only when enabled.

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17576	4120	4112	4112
q2	2063	322	207	207
q3	10220	1395	806	806
q4	4686	492	344	344
q5	7562	853	567	567
q6	184	178	144	144
q7	757	786	590	590
q8	9327	1623	1572	1572
q9	5240	4101	4045	4045
q10	6742	1658	1410	1410
q11	516	362	342	342
q12	736	593	473	473
q13	18078	3259	2782	2782
q14	260	256	233	233
q15	q16	729	731	662	662
q17	956	996	1009	996
q18	6560	5599	5607	5599
q19	1134	1199	1097	1097
q20	799	664	561	561
q21	5557	2663	2470	2470
q22	430	375	312	312
Total cold run time: 100112 ms
Total hot run time: 29324 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4429	4305	4311	4305
q2	282	336	204	204
q3	4548	4959	4367	4367
q4	2164	2256	1407	1407
q5	4279	4173	4122	4122
q6	231	182	139	139
q7	1682	1602	1441	1441
q8	2767	2175	2142	2142
q9	7572	7405	7569	7405
q10	4376	4286	3900	3900
q11	592	412	387	387
q12	713	739	520	520
q13	3330	3614	2971	2971
q14	308	292	261	261
q15	q16	710	732	624	624
q17	1315	1295	1298	1295
q18	12218	11130	11781	11130
q19	1151	1114	1193	1114
q20	2263	2212	1923	1923
q21	5718	5026	4971	4971
q22	540	498	428	428
Total cold run time: 61188 ms
Total hot run time: 55056 ms

@hello-stephen

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

query5	4333	618	464	464
query6	469	220	215	215
query7	4863	624	335	335
query8	326	172	155	155
query9	8778	4062	4086	4062
query10	462	367	336	336
query11	5841	2238	1988	1988
query12	151	99	96	96
query13	1238	639	448	448
query14	6065	4400	3986	3986
query14_1	3822	3801	3852	3801
query15	207	203	179	179
query16	989	474	466	466
query17	928	721	558	558
query18	2458	487	342	342
query19	212	198	160	160
query20	105	100	109	100
query21	232	165	145	145
query22	12971	13105	13515	13105
query23	16288	15410	14969	14969
query23_1	15056	14633	14704	14633
query24	7461	1716	1261	1261
query24_1	1272	1270	1258	1258
query25	525	414	357	357
query26	1320	347	207	207
query27	2603	593	376	376
query28	4534	2060	2050	2050
query29	1059	605	470	470
query30	341	261	226	226
query31	1192	1131	1040	1040
query32	121	61	58	58
query33	503	305	229	229
query34	1190	1128	648	648
query35	754	764	627	627
query36	783	763	682	682
query37	151	105	92	92
query38	1831	1772	1697	1697
query39	837	823	794	794
query39_1	768	766	781	766
query40	241	163	136	136
query41	61	60	60	60
query42	91	92	91	91
query43	329	322	269	269
query44	1484	781	765	765
query45	186	174	165	165
query46	1051	1205	743	743
query47	1524	1516	1435	1435
query48	401	401	308	308
query49	585	421	288	288
query50	1081	436	335	335
query51	10524	10381	10555	10381
query52	85	83	73	73
query53	267	278	202	202
query54	284	255	214	214
query55	76	74	69	69
query56	298	293	294	293
query57	1009	992	925	925
query58	285	267	257	257
query59	1540	1654	1353	1353
query60	311	273	258	258
query61	151	151	151	151
query62	402	342	275	275
query63	244	190	202	190
query64	3026	1183	989	989
query65	3902	3833	3839	3833
query66	1831	518	368	368
query67	28147	28127	27985	27985
query68	3083	1558	1064	1064
query69	410	310	311	310
query70	865	800	790	790
query71	383	326	311	311
query72	3112	2670	2329	2329
query73	860	770	450	450
query74	4644	4513	4299	4299
query75	2496	2427	1991	1991
query76	2305	1196	783	783
query77	344	373	280	280
query78	11431	11127	10537	10537
query79	1331	1178	795	795
query80	682	542	496	496
query81	452	330	288	288
query82	627	185	146	146
query83	384	327	296	296
query84	340	157	132	132
query85	929	601	517	517
query86	321	231	250	231
query87	2011	2013	1843	1843
query88	3778	2884	2798	2798
query89	405	332	289	289
query90	1943	197	208	197
query91	202	189	164	164
query92	62	60	54	54
query93	1569	1533	1008	1008
query94	550	363	321	321
query95	791	589	452	452
query96	1039	834	353	353
query97	2500	2449	2310	2310
query98	203	185	180	180
query99	733	726	628	628
Total cold run time: 253233 ms
Total hot run time: 167349 ms

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 32.61% (15/46) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.25	0.14	0.13
query4	1.61	0.14	0.14
query5	0.24	0.22	0.21
query6	1.16	0.82	0.80
query7	0.04	0.01	0.00
query8	0.07	0.05	0.04
query9	0.37	0.31	0.31
query10	0.57	0.56	0.59
query11	0.18	0.14	0.14
query12	0.18	0.14	0.14
query13	0.48	0.48	0.47
query14	1.00	0.99	0.99
query15	0.62	0.61	0.58
query16	0.32	0.30	0.32
query17	1.08	1.17	1.07
query18	0.22	0.20	0.19
query19	2.09	1.95	1.98
query20	0.02	0.01	0.01
query21	15.44	0.22	0.13
query22	4.87	0.06	0.05
query23	16.13	0.30	0.13
query24	3.00	0.41	0.31
query25	0.10	0.05	0.05
query26	0.74	0.20	0.16
query27	0.03	0.03	0.03
query28	3.47	0.76	0.37
query29	12.47	4.01	3.18
query30	0.27	0.15	0.16
query31	2.77	0.54	0.30
query32	3.22	0.59	0.48
query33	3.06	3.16	3.31
query34	15.66	3.94	3.29
query35	3.25	3.15	3.24
query36	0.56	0.45	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.16	0.15	0.14
query41	0.08	0.04	0.03
query42	0.04	0.02	0.02
query43	0.04	0.04	0.03
Total cold run time: 96.15 s
Total hot run time: 23.81 s

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.

4 participants