Skip to content

[improvement](scan) Align scanner split to segments for MATCH - #67915

Open
csun5285 wants to merge 1 commit into
apache:masterfrom
csun5285:scan-segment-aligned-split-for-match
Open

csun5285 wants to merge 1 commit into
apache:masterfrom
csun5285:scan-segment-aligned-split-for-match

Conversation

@csun5285

@csun5285 csun5285 commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

An inverted index query is run over the whole segment and only then intersected with the scanner's
row range, so its cost is priced per segment while ParallelScannerBuilder splits by rows. A
segment shared by two scanners gets its posting lists walked twice.

An ann topn has the same property and already asks for one scanner per segment. This PR reuses that
path for MATCH, so both of these now build one scanner per segment:

SELECT k1 FROM t ORDER BY l2_distance_approximate(embedding, [1.0, 2.0]) LIMIT 2;  -- already did
SELECT k1 FROM t WHERE msg MATCH_PHRASE 'error timeout';                          -- new

Cloud mode only. Queries without MATCH or ann topn are unchanged.

Related PR: #xxx

Problem Summary:

### Release note

None

### Check List (For Author)

- Test <!-- At least one of them must be included. -->
    - [ ] 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.
        - [x] Other reason <!-- Add your reason?  -->

- Behavior changed:
    - [ ] No.
    - [ ] Yes. <!-- Explain the behavior change -->

- Does this need documentation?
    - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg: https://github.com/apache/doris-website/pull/1214 -->

### Check List (For Reviewer who merge this PR)

- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR should merge into -->

@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?

@csun5285
csun5285 force-pushed the scan-segment-aligned-split-for-match branch from f57184f to 87407c5 Compare September 13, 2026 14:22
@csun5285

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17559	3055	3030	3030
q2	2111	253	237	237
q3	10249	911	510	510
q4	4669	245	205	205
q5	7676	556	375	375
q6	134	114	93	93
q7	524	497	395	395
q8	9257	854	924	854
q9	3414	2403	2382	2382
q10	6514	845	734	734
q11	391	200	174	174
q12	631	259	197	197
q13	18096	1551	1164	1164
q14	155	147	139	139
q15	q16	439	395	366	366
q17	1363	877	813	813
q18	3111	2259	2278	2259
q19	1258	902	762	762
q20	367	296	203	203
q21	5566	1718	1872	1718
q22	327	272	234	234
Total cold run time: 93811 ms
Total hot run time: 16844 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3407	3352	3378	3352
q2	498	399	372	372
q3	2254	2440	2156	2156
q4	1198	1164	894	894
q5	2180	2133	2112	2112
q6	166	119	89	89
q7	1059	946	885	885
q8	1584	1395	1396	1395
q9	3157	3182	3129	3129
q10	1888	1776	1660	1660
q11	361	270	258	258
q12	455	431	346	346
q13	1479	1524	1153	1153
q14	174	175	162	162
q15	q16	398	395	356	356
q17	3631	3329	3284	3284
q18	4825	4407	4731	4407
q19	854	920	887	887
q20	989	960	815	815
q21	3743	3051	3168	3051
q22	402	352	330	330
Total cold run time: 34702 ms
Total hot run time: 31093 ms

@hello-stephen

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

query5	4266	419	337	337
query6	395	158	125	125
query7	4917	439	225	225
query8	287	127	119	119
query9	8703	2899	2926	2899
query10	384	228	186	186
query11	5378	1034	924	924
query12	114	74	76	74
query13	1194	456	319	319
query14	6093	2196	2085	2085
query14_1	2000	1981	1973	1973
query15	169	125	111	111
query16	936	365	344	344
query17	798	442	356	356
query18	2321	321	236	236
query19	163	140	132	132
query20	72	67	67	67
query21	200	101	86	86
query22	5513	5368	5234	5234
query23	6630	6091	6106	6091
query23_1	6112	6223	6137	6137
query24	7304	1073	777	777
query24_1	769	784	777	777
query25	401	277	227	227
query26	1085	218	126	126
query27	2785	427	257	257
query28	4638	1499	1476	1476
query29	930	407	321	321
query30	263	155	130	130
query31	822	400	328	328
query32	125	70	75	70
query33	443	219	177	177
query34	993	823	495	495
query35	395	404	351	351
query36	573	550	561	550
query37	119	78	71	71
query38	1007	856	837	837
query39	496	483	471	471
query39_1	508	468	452	452
query40	200	91	77	77
query41	54	50	49	49
query42	76	72	73	72
query43	242	240	210	210
query44	1019	540	540	540
query45	113	109	101	101
query46	730	806	522	522
query47	744	768	711	711
query48	319	314	219	219
query49	536	234	189	189
query50	760	271	195	195
query51	8212	8069	8145	8069
query52	68	69	61	61
query53	202	199	152	152
query54	210	194	167	167
query55	74	65	57	57
query56	197	180	186	180
query57	703	670	650	650
query58	212	164	180	164
query59	1241	1239	1107	1107
query60	242	184	183	183
query61	139	129	168	129
query62	358	214	182	182
query63	175	136	137	136
query64	2530	657	594	594
query65	1606	1607	1609	1607
query66	1835	288	214	214
query67	9908	9776	9667	9667
query68	2774	1210	744	744
query69	339	210	201	201
query70	695	620	625	620
query71	250	172	156	156
query72	2270	1712	1461	1461
query73	655	574	336	336
query74	1557	1223	1164	1164
query75	1185	1092	967	967
query76	2288	720	507	507
query77	261	257	201	201
query78	3867	3586	3207	3207
query79	2888	856	571	571
query80	1580	339	274	274
query81	526	156	133	133
query82	621	142	100	100
query83	282	206	191	191
query84	291	109	89	89
query85	818	333	286	286
query86	485	170	164	164
query87	1017	983	891	891
query88	3081	2107	2128	2107
query89	281	199	171	171
query90	2126	136	131	131
query91	129	122	101	101
query92	95	70	71	70
query93	2284	1111	660	660
query94	626	267	196	196
query95	510	312	219	219
query96	849	642	267	267
query97	1090	1073	1015	1015
query98	175	141	133	133
query99	446	349	307	307
Total cold run time: 178778 ms
Total hot run time: 81971 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.07	0.03	0.04
query3	0.24	0.11	0.10
query4	1.60	0.10	0.10
query5	0.17	0.17	0.17
query6	1.25	0.67	0.70
query7	0.03	0.00	0.01
query8	0.04	0.03	0.02
query9	0.29	0.22	0.22
query10	0.33	0.34	0.33
query11	0.17	0.12	0.11
query12	0.15	0.12	0.12
query13	0.31	0.31	0.30
query14	0.46	0.44	0.45
query15	0.37	0.36	0.35
query16	0.21	0.23	0.24
query17	0.68	0.70	0.66
query18	0.19	0.16	0.16
query19	1.18	1.15	1.20
query20	0.01	0.01	0.01
query21	15.42	0.17	0.11
query22	5.06	0.04	0.04
query23	16.19	0.25	0.10
query24	2.99	0.30	0.28
query25	0.10	0.04	0.04
query26	0.83	0.17	0.12
query27	0.04	0.03	0.02
query28	3.66	0.55	0.29
query29	12.42	3.20	2.55
query30	0.25	0.12	0.12
query31	2.75	0.37	0.17
query32	3.54	0.31	0.22
query33	1.37	1.40	1.46
query34	15.40	2.19	1.76
query35	1.75	1.75	1.72
query36	0.47	0.29	0.30
query37	0.06	0.04	0.04
query38	0.06	0.03	0.03
query39	0.03	0.02	0.02
query40	0.11	0.09	0.08
query41	0.08	0.03	0.02
query42	0.04	0.03	0.02
query43	0.03	0.03	0.02
Total cold run time: 90.41 s
Total hot run time: 14.63 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 0.00% (0/1) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 63.26% (29629/46840)
Line Coverage 48.17% (309564/642587)
Region Coverage 43.71% (249249/570243)
Branch Coverage 45.31% (116058/256129)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100.00% (1/1) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.31% (34625/45373)
Line Coverage 61.26% (389219/635306)
Region Coverage 57.51% (326705/568045)
Branch Coverage 58.32% (148950/255393)

@csun5285
csun5285 force-pushed the scan-segment-aligned-split-for-match branch 2 times, most recently from 7651394 to 74f34f4 Compare September 14, 2026 02:57
@csun5285

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17598	3037	3056	3037
q2	2088	249	220	220
q3	10283	890	515	515
q4	4672	247	203	203
q5	7677	564	380	380
q6	138	116	97	97
q7	525	492	381	381
q8	9229	850	914	850
q9	3446	2434	2391	2391
q10	6487	848	710	710
q11	396	197	179	179
q12	618	262	202	202
q13	18128	1541	1202	1202
q14	162	150	139	139
q15	q16	438	402	370	370
q17	1324	861	804	804
q18	3174	2353	2296	2296
q19	1273	857	742	742
q20	379	283	201	201
q21	5615	1745	1851	1745
q22	345	271	237	237
Total cold run time: 93995 ms
Total hot run time: 16901 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3359	3321	3293	3293
q2	511	395	421	395
q3	2263	2295	2140	2140
q4	1218	1184	890	890
q5	2237	2170	2154	2154
q6	170	123	88	88
q7	1032	946	863	863
q8	1604	1390	1395	1390
q9	3230	3187	3185	3185
q10	1903	1824	1671	1671
q11	359	276	250	250
q12	452	428	343	343
q13	1490	1562	1169	1169
q14	176	172	163	163
q15	q16	392	390	362	362
q17	3709	3367	3245	3245
q18	4979	4585	4886	4585
q19	1023	855	863	855
q20	1034	1010	860	860
q21	3901	3206	3145	3145
q22	411	334	313	313
Total cold run time: 35453 ms
Total hot run time: 31359 ms

@hello-stephen

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

query5	4255	429	349	349
query6	384	139	130	130
query7	4914	433	237	237
query8	299	129	120	120
query9	8686	2838	2830	2830
query10	400	226	182	182
query11	5379	1064	937	937
query12	119	73	72	72
query13	1205	454	326	326
query14	6112	2251	2152	2152
query14_1	2030	2024	2012	2012
query15	173	124	115	115
query16	911	377	358	358
query17	803	474	364	364
query18	2332	338	246	246
query19	162	135	109	109
query20	90	73	72	72
query21	205	102	89	89
query22	5526	5507	5418	5418
query23	6772	6213	6067	6067
query23_1	6278	6370	6132	6132
query24	7289	1079	793	793
query24_1	776	817	774	774
query25	427	298	250	250
query26	1232	225	135	135
query27	2787	421	255	255
query28	4691	1486	1478	1478
query29	956	429	343	343
query30	261	154	131	131
query31	846	412	342	342
query32	128	74	74	74
query33	461	230	172	172
query34	973	832	487	487
query35	406	413	358	358
query36	564	574	536	536
query37	116	84	70	70
query38	1028	879	842	842
query39	506	478	481	478
query39_1	478	461	470	461
query40	211	95	85	85
query41	58	57	56	56
query42	75	72	74	72
query43	246	248	218	218
query44	986	519	545	519
query45	112	114	101	101
query46	751	820	521	521
query47	782	766	710	710
query48	318	317	255	255
query49	527	231	184	184
query50	737	260	188	188
query51	8183	7967	8008	7967
query52	67	71	66	66
query53	188	212	159	159
query54	212	176	158	158
query55	71	59	56	56
query56	282	167	164	164
query57	723	675	683	675
query58	190	158	160	158
query59	1253	1266	1121	1121
query60	223	164	182	164
query61	127	124	109	109
query62	354	202	174	174
query63	183	151	140	140
query64	2693	672	578	578
query65	1713	1645	1732	1645
query66	1934	275	213	213
query67	9934	9914	9787	9787
query68	2766	1168	758	758
query69	347	213	185	185
query70	676	638	604	604
query71	248	180	160	160
query72	2291	1663	1507	1507
query73	639	609	339	339
query74	1587	1233	1152	1152
query75	1192	1109	970	970
query76	2288	697	529	529
query77	244	264	212	212
query78	3946	3739	3280	3280
query79	2876	821	605	605
query80	1572	333	275	275
query81	504	158	132	132
query82	616	127	95	95
query83	272	207	185	185
query84	299	109	86	86
query85	804	337	277	277
query86	465	174	174	174
query87	1026	981	912	912
query88	2988	2096	2057	2057
query89	290	194	173	173
query90	2132	131	119	119
query91	129	116	93	93
query92	103	71	64	64
query93	2164	1122	678	678
query94	668	260	211	211
query95	544	244	289	244
query96	766	556	277	277
query97	1059	1037	1047	1037
query98	179	131	133	131
query99	421	341	306	306
Total cold run time: 179611 ms
Total hot run time: 82586 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.08	0.05	0.04
query3	0.24	0.11	0.10
query4	1.60	0.11	0.10
query5	0.17	0.15	0.15
query6	1.27	0.74	0.68
query7	0.04	0.01	0.00
query8	0.05	0.03	0.04
query9	0.28	0.22	0.22
query10	0.38	0.35	0.35
query11	0.17	0.12	0.11
query12	0.14	0.12	0.12
query13	0.30	0.31	0.31
query14	0.46	0.45	0.46
query15	0.38	0.34	0.36
query16	0.24	0.20	0.23
query17	0.69	0.74	0.73
query18	0.19	0.17	0.17
query19	1.13	1.18	1.14
query20	0.02	0.01	0.01
query21	15.44	0.16	0.12
query22	5.05	0.05	0.05
query23	16.20	0.25	0.10
query24	3.01	0.32	0.25
query25	0.11	0.04	0.03
query26	0.76	0.16	0.13
query27	0.04	0.03	0.03
query28	3.62	0.57	0.28
query29	12.43	3.17	2.54
query30	0.25	0.12	0.13
query31	2.75	0.38	0.17
query32	3.52	0.32	0.23
query33	1.40	1.41	1.42
query34	15.38	2.18	1.78
query35	1.77	1.77	1.75
query36	0.46	0.30	0.27
query37	0.06	0.04	0.04
query38	0.05	0.03	0.03
query39	0.03	0.02	0.03
query40	0.11	0.08	0.07
query41	0.07	0.03	0.02
query42	0.03	0.02	0.03
query43	0.03	0.02	0.03
Total cold run time: 90.41 s
Total hot run time: 14.73 s

@csun5285
csun5285 force-pushed the scan-segment-aligned-split-for-match branch from 74f34f4 to f4ab2d5 Compare September 14, 2026 06:58
`SegmentIterator::_lazy_init` runs the inverted index query over the whole
segment first and only then intersects the result with `_opts.row_ranges`. The
cost of a MATCH predicate is therefore priced per segment, while
`ParallelScannerBuilder` splits by rows. When a segment ends up shared by two
scanners, its posting lists are walked once per scanner.

An ann topn is priced per segment for the same reason and already asks for one
scanner per segment through `optimize_index_scan_parallelism`. Reuse that path
for MATCH: `_use_scan_parallelism_by_per_segment()` now decides both cases, and
`_build_scanners_by_per_segment` gives every segment a scanner of its own, so a
split boundary never falls inside a segment.

The MATCH branch applies in cloud mode only. A query without MATCH and without
an ann topn keeps taking `_build_scanners_by_rowid` and behaves exactly as
before. Note that the predicate also matches `search()` and `multi_match()`,
which are priced per segment in the same way.

Measured on a cloud cluster, cold query (file cache cleared and BE restarted
between runs). `NumSegmentTotal` counts how many times a segment is opened, so
it is the direct measure of the duplicated work this removes:

  8 segments over 4 rowsets, 20M rows
                            before     after
    NumScanners                 10         8
    NumSegmentTotal             16         8    duplicate reads removed
    InvertedIndexQueryTime   5.01s     2.55s    -49%
    Total                    801ms     627ms    -22%

  40 segments over 40 rowsets, 2M rows
                            before     after
    NumScanners                  1        40
    NumSegmentTotal             40        40    nothing to remove
    InvertedIndexQueryTime    323ms     411ms   +27%
    Total                     403ms      69ms   -83%

The gain comes from dropping duplicate segment reads, so it depends on the
geometry. When the row split cuts segments apart the index work roughly halves.
When it does not - many small rowsets, one segment each - there is no duplicate
work to remove and the index cost grows by the extra per-scanner setup, while
the wall clock drops because the scan is no longer serialized behind a single
scanner.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VgV4Zy5NaEYpUP4Yrh1yWn
@csun5285
csun5285 force-pushed the scan-segment-aligned-split-for-match branch from f4ab2d5 to 5a5f430 Compare September 14, 2026 08:25
@csun5285

Copy link
Copy Markdown
Contributor Author

/review

@csun5285

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.

Request changes: the cloud MATCH route reaches the intended segment-aligned builder, but the current implementation introduces one result-correctness regression and three substantial performance/coverage defects. The inline comments cover: incompatible rowset-local BM25 statistics for score TopN; unbounded scanner/delegate/task creation that ignores the configured cap; false-positive routing when MATCH will execute only via row fallback; and omission of supported MATCH virtual-column projections.

Critical checkpoint conclusions:

  • Goal and test proof: ordinary cloud filter MATCH does enter the segment-aligned route, but the four issues prevent the change from safely accomplishing its goal. The PR adds no unit/regression test and checks no test box.
  • Scope and focus: the two-file change is mechanically small, but the selector is not aligned with the full set of index-executable paths and the reused builder has semantics the new automatic caller cannot safely inherit unchanged.
  • Concurrency: scanner construction precedes worker scheduling; no new data race, lock-order issue, or deadlock was found. The concurrency-related defect is eager cardinality before admission, reported inline.
  • Lifecycle: no ownership cycle or static-initialization issue was found. Scanner/delegate/task objects are eventually released, but one of each is retained per segment until cancellation/close.
  • Configuration: no new option is added. The route disregards existing parallel_scan_max_scanners_count/minimum-row behavior, and it does not honor enable_inverted_index_query when deciding whether the optimization has any index work to reuse.
  • Compatibility: no protocol, function-symbol, storage-format, or rolling-upgrade compatibility change was found.
  • Parallel paths: non-cloud, serial, binlog/TSO, aggregate/merge, and ANN-only gating remain unchanged. The supported virtual-column projection path is omitted and is reported inline.
  • Conditions and errors: cloud/common-expression timing is valid, but expression-tree presence is not sufficient evidence that SegmentIterator will dispatch inverted-index evaluation. No separate error-propagation defect was found.
  • Tests: existing score, no-index, projection, and ANN/fulltext tests do not cover cloud multi-rowset BM25 comparability, scanner-cap adherence, or positive/negative selector cases. No builds or tests were run because this review runner explicitly prohibits them; visible CI currently proves formatting/light checks only, with build/test jobs skipped.
  • Observability: existing scanner/index counters are adequate; no separate observability blocker was found.
  • Persistence and writes: transactions, committed-version visibility, delete bitmap/version propagation, persistence, and write paths are not changed; captured query read-source restrictions were traced and preserved.
  • FE/BE variables: no new cross-layer variable or serialization field is introduced.
  • Performance: besides the unbounded object population and lost slow-path row parallelism, score-enabled N-segment rowsets can repeat full-rowset collection-statistics work N times.
  • Other: no additional user-provided focus was supplied. Two full rounds converged with every candidate accepted, merged, or dismissed and all round-two agents returning NO_NEW_VALUABLE_FINDINGS.

// Find MATCH recursively; ones nested in AND / OR / NOT count too.
static bool is_match_expr(const VExprSPtr& expr) {
DORIS_CHECK(expr != nullptr);
if (expr->node_type() == TExprNodeType::MATCH_PRED ||

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] Gate this on index execution, not only on expression shape. With enable_inverted_index_query=false (or a MATCH column without an iterator), this still returns true even though SegmentIterator skips index evaluation and runs the supported row fallback. On a single large segment, the old row-count builder can split that expensive fallback across scanners, while this route creates exactly one scanner and serializes it; on many segments it also triggers the unbounded population noted separately. Row-only wrappers have the same false positive because their roots never dispatch evaluate_inverted_index() to the MATCH child. Require index execution to be enabled and a usable/index-evaluable root before selecting this strategy.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

在cloud 上可以认为 match 的执行一定有倒排索引的

state()->query_options().optimize_index_scan_parallelism && _ann_topn_runtime != nullptr) {
return true;
}
return config::is_cloud_mode() &&

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] Preserve global BM25 statistics before splitting by segment. This branch also covers score-enabled MATCH/SEARCH scans. Each generated scanner gets one segment from one rowset, and OlapScanner::_prepare_impl() builds a fresh CollectionStatistics from only that scanner's rs_splits; those rowset-local document-frequency and length values feed BM25. Rows from different rowsets are therefore ranked with incompatible IDF/avgdl values, so a final ORDER BY score() LIMIT ... can return the wrong row. Also, collection walks every segment of the supplied rowset, so an N-segment rowset now repeats that work N times. Compute/share statistics from the original complete read source, or keep score queries on the prior strategy, and add a cloud multi-rowset TopN regression.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

CollectionStatistics 一直是按scanner 的粒度构建的

return true;
}
return config::is_cloud_mode() &&
std::ranges::any_of(_common_expr_ctxs_push_down,

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] Include pushed-down MATCH virtual-column projections in this decision. Projection-only MATCH is stored in _slot_id_to_virtual_column_expr, not _common_expr_ctxs_push_down, yet every scanner clones that context and SegmentIterator evaluates it over num_rows() for the whole segment before materializing the selected row range. A large segment split among N scanners therefore still repeats the same index evaluation N times, so this misses a supported path with the exact cost the PR targets. Inspect the virtual-column roots here as well (including any VirtualSlotRef unwrapping) and add a cloud projection regression.

@csun5285 csun5285 Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

不考虑 projection 先,仅针对 where 后面的倒排索引计算

scanner_builder.set_scan_parallelism_by_per_segment(true);
}
}
scanner_builder.set_scan_parallelism_by_per_segment(_use_scan_parallelism_by_per_segment());

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] Keep segment-aligned scans within the configured scanner cap. _build_scanners_by_per_segment() creates one scanner for every segment and never consults parallel_scan_max_scanners_count or the minimum-rows setting; initialization then creates a delegate and pending task for every scanner before execution concurrency is applied. A cloud table with many historical segments can therefore allocate an unbounded scanner/task population even with the cap set to 1, and LIMIT/cancellation only clean it up afterward. Group whole segments into at most the configured number of scanner read sources so no segment is split while scanner cardinality remains bounded.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

scanner 变多的代价很低

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17569	3018	3042	3018
q2	2088	271	218	218
q3	9956	839	518	518
q4	4676	255	203	203
q5	7666	567	395	395
q6	138	118	96	96
q7	531	482	385	385
q8	9233	870	899	870
q9	3544	2424	2426	2424
q10	6522	876	729	729
q11	393	199	179	179
q12	636	261	200	200
q13	18130	1581	1146	1146
q14	155	158	143	143
q15	q16	456	402	368	368
q17	1383	857	732	732
q18	3141	2333	2288	2288
q19	2012	860	759	759
q20	385	277	198	198
q21	5620	1910	1837	1837
q22	333	275	224	224
Total cold run time: 94567 ms
Total hot run time: 16930 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3371	3314	3328	3314
q2	516	406	370	370
q3	2272	2410	2218	2218
q4	1228	1192	916	916
q5	2225	2177	2162	2162
q6	168	129	89	89
q7	1036	958	874	874
q8	1582	1399	1417	1399
q9	3252	3209	3218	3209
q10	1903	1856	1670	1670
q11	364	277	260	260
q12	461	436	342	342
q13	1474	1542	1174	1174
q14	172	170	166	166
q15	q16	399	395	360	360
q17	3705	3433	3201	3201
q18	4931	4526	5119	4526
q19	937	853	844	844
q20	1039	979	829	829
q21	3842	3230	3224	3224
q22	383	343	321	321
Total cold run time: 35260 ms
Total hot run time: 31468 ms

@hello-stephen

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

query5	4255	398	328	328
query6	383	140	118	118
query7	4990	394	228	228
query8	291	119	120	119
query9	8684	2873	2866	2866
query10	395	212	180	180
query11	5385	1055	921	921
query12	124	72	72	72
query13	1192	434	337	337
query14	6104	2253	2136	2136
query14_1	2027	2017	2004	2004
query15	174	123	108	108
query16	904	364	349	349
query17	777	452	351	351
query18	2351	328	229	229
query19	163	135	109	109
query20	72	72	71	71
query21	197	102	86	86
query22	5587	5644	5599	5599
query23	6973	6376	5979	5979
query23_1	6136	6091	6105	6091
query24	7280	1088	789	789
query24_1	760	790	806	790
query25	428	299	247	247
query26	1243	237	131	131
query27	2804	432	263	263
query28	4681	1495	1502	1495
query29	935	441	340	340
query30	253	158	130	130
query31	838	413	339	339
query32	137	80	75	75
query33	459	214	182	182
query34	1006	821	493	493
query35	405	434	346	346
query36	567	566	540	540
query37	121	81	68	68
query38	1027	852	852	852
query39	511	522	489	489
query39_1	468	453	472	453
query40	209	95	81	81
query41	59	56	55	55
query42	79	72	75	72
query43	243	242	208	208
query44	997	541	534	534
query45	117	109	103	103
query46	765	832	531	531
query47	778	775	726	726
query48	317	341	232	232
query49	528	229	191	191
query50	800	259	184	184
query51	8075	7883	8047	7883
query52	68	79	60	60
query53	191	196	142	142
query54	201	176	140	140
query55	73	61	61	61
query56	317	155	182	155
query57	714	700	658	658
query58	198	164	157	157
query59	1252	1275	1150	1150
query60	251	171	168	168
query61	116	111	109	109
query62	360	203	192	192
query63	167	136	137	136
query64	2831	730	561	561
query65	1718	1652	1660	1652
query66	1799	262	201	201
query67	10191	10046	9864	9864
query68	3017	1161	742	742
query69	377	224	189	189
query70	699	610	594	594
query71	252	179	161	161
query72	2296	1677	1505	1505
query73	645	611	339	339
query74	2009	1253	1165	1165
query75	1194	1117	988	988
query76	2389	718	496	496
query77	250	260	207	207
query78	4098	3914	3253	3253
query79	2294	819	571	571
query80	1604	329	273	273
query81	498	159	134	134
query82	626	121	97	97
query83	278	209	189	189
query84	287	111	92	92
query85	777	328	278	278
query86	380	171	168	168
query87	1036	985	913	913
query88	2774	2095	2068	2068
query89	277	195	177	177
query90	1998	125	123	123
query91	131	121	95	95
query92	72	70	70	70
query93	1456	1047	715	715
query94	648	246	228	228
query95	532	321	228	228
query96	783	557	257	257
query97	1086	1083	1061	1061
query98	165	143	130	130
query99	429	343	319	319
Total cold run time: 179264 ms
Total hot run time: 82554 ms

@hello-stephen

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

query1	0.01	0.00	0.01
query2	0.08	0.04	0.03
query3	0.26	0.11	0.11
query4	1.60	0.10	0.09
query5	0.17	0.16	0.16
query6	1.26	0.69	0.69
query7	0.03	0.01	0.00
query8	0.04	0.02	0.03
query9	0.28	0.21	0.21
query10	0.34	0.36	0.35
query11	0.16	0.11	0.11
query12	0.15	0.12	0.13
query13	0.33	0.30	0.31
query14	0.46	0.46	0.46
query15	0.38	0.35	0.35
query16	0.24	0.22	0.23
query17	0.71	0.70	0.69
query18	0.16	0.15	0.16
query19	1.27	1.20	1.23
query20	0.01	0.01	0.01
query21	15.48	0.15	0.12
query22	5.07	0.05	0.04
query23	16.20	0.28	0.10
query24	2.99	0.32	0.25
query25	0.09	0.03	0.05
query26	0.76	0.17	0.12
query27	0.04	0.04	0.04
query28	3.67	0.58	0.28
query29	12.41	3.16	2.55
query30	0.26	0.11	0.12
query31	2.75	0.39	0.17
query32	3.52	0.32	0.23
query33	1.37	1.48	1.50
query34	15.39	2.25	1.80
query35	1.76	1.75	1.72
query36	0.47	0.30	0.29
query37	0.06	0.04	0.04
query38	0.04	0.02	0.02
query39	0.03	0.02	0.03
query40	0.12	0.08	0.08
query41	0.07	0.02	0.02
query42	0.03	0.02	0.02
query43	0.03	0.03	0.03
Total cold run time: 90.55 s
Total hot run time: 14.83 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100% (0/0) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.14% (34267/45003)
Line Coverage 61.04% (384652/630148)
Region Coverage 57.51% (324123/563638)
Branch Coverage 58.22% (147431/253216)

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.

3 participants