@@ -16,19 +16,31 @@ use std::any::Any;
1616use std:: collections:: HashMap ;
1717
1818use databend_common_catalog:: plan:: DataSourcePlan ;
19+ use databend_common_catalog:: plan:: NUM_ROW_ID_PREFIX_BITS ;
1920use databend_common_exception:: ErrorCode ;
2021use databend_common_exception:: Result ;
22+ use databend_common_expression:: ColumnRef ;
23+ use databend_common_expression:: Constant ;
2124use databend_common_expression:: DataField ;
25+ use databend_common_expression:: Expr ;
2226use databend_common_expression:: ROW_ID_COL_NAME ;
27+ use databend_common_expression:: Scalar ;
28+ use databend_common_expression:: type_check:: check_function;
29+ use databend_common_expression:: types:: DataType ;
30+ use databend_common_expression:: types:: NumberDataType ;
31+ use databend_common_functions:: BUILTIN_FUNCTIONS ;
2332use databend_common_pipeline:: core:: ProcessorPtr ;
2433use databend_common_pipeline_transforms:: filters:: TransformLimit ;
2534use databend_common_sql:: ColumnEntry ;
2635use databend_common_sql:: ColumnSet ;
2736use databend_common_sql:: IndexType ;
2837use databend_common_sql:: Symbol ;
38+ use databend_common_sql:: executor:: physical_plans:: FragmentKind ;
2939use databend_common_sql:: optimizer:: ir:: SExpr ;
3040
41+ use crate :: physical_plans:: Exchange ;
3142use crate :: physical_plans:: PhysicalPlanBuilder ;
43+ use crate :: physical_plans:: Sort ;
3244use crate :: physical_plans:: explain:: PlanStatsInfo ;
3345use crate :: physical_plans:: format:: LimitFormatter ;
3446use crate :: physical_plans:: format:: PhysicalFormat ;
@@ -37,6 +49,7 @@ use crate::physical_plans::physical_plan::PhysicalPlan;
3749use crate :: physical_plans:: physical_plan:: PhysicalPlanCast ;
3850use crate :: physical_plans:: physical_plan:: PhysicalPlanMeta ;
3951use crate :: physical_plans:: physical_row_fetch:: RowFetch ;
52+ use crate :: physical_plans:: physical_sort:: SortStep ;
4053use crate :: pipelines:: PipelineBuilder ;
4154
4255#[ derive( Clone , Debug , serde:: Serialize , serde:: Deserialize ) ]
@@ -130,6 +143,44 @@ impl IPhysicalPlan for Limit {
130143}
131144
132145impl PhysicalPlanBuilder {
146+ fn contains_merge_exchange ( plan : & PhysicalPlan ) -> bool {
147+ if let Some ( exchange) = Exchange :: from_physical_plan ( plan)
148+ && exchange. kind == FragmentKind :: Merge
149+ {
150+ return true ;
151+ }
152+
153+ plan. children ( ) . any ( Self :: contains_merge_exchange)
154+ }
155+
156+ fn build_row_fetch_shuffle_key (
157+ input_schema : & databend_common_expression:: DataSchema ,
158+ row_id_col_offset : usize ,
159+ ) -> Result < databend_common_expression:: RemoteExpr > {
160+ let row_id_field = input_schema. field ( row_id_col_offset) ;
161+ let row_id_expr = Expr :: ColumnRef ( ColumnRef {
162+ span : None ,
163+ id : row_id_col_offset,
164+ data_type : row_id_field. data_type ( ) . clone ( ) ,
165+ display_name : row_id_field. name ( ) . to_string ( ) ,
166+ } ) ;
167+ let block_prefix = check_function (
168+ None ,
169+ "bit_shift_right" ,
170+ & [ ] ,
171+ & [
172+ row_id_expr,
173+ Expr :: Constant ( Constant {
174+ span : None ,
175+ scalar : Scalar :: Number ( ( ( 64 - NUM_ROW_ID_PREFIX_BITS ) as u64 ) . into ( ) ) ,
176+ data_type : DataType :: Number ( NumberDataType :: UInt64 ) ,
177+ } ) ,
178+ ] ,
179+ & BUILTIN_FUNCTIONS ,
180+ ) ?;
181+ Ok ( block_prefix. as_remote_expr ( ) )
182+ }
183+
133184 pub async fn build_limit (
134185 & mut self ,
135186 s_expr : & SExpr ,
@@ -164,6 +215,7 @@ impl PhysicalPlanBuilder {
164215 }
165216
166217 // If `lazy_columns` is not empty, build a `RowFetch` plan on top of the `Limit` plan.
218+ let order_by = Sort :: from_physical_plan ( & input_plan) . map ( |sort| sort. order_by . clone ( ) ) ;
167219 let mut plan = PhysicalPlan :: new ( Limit {
168220 meta : PhysicalPlanMeta :: new ( "Limit" ) ,
169221 input : input_plan,
@@ -220,6 +272,16 @@ impl PhysicalPlanBuilder {
220272
221273 let mut table_indexes: Vec < IndexType > = lazy_columns_by_table. keys ( ) . copied ( ) . collect ( ) ;
222274 table_indexes. sort_unstable ( ) ;
275+ let max_threads = self . ctx . get_settings ( ) . get_max_threads ( ) ? as usize ;
276+ // A local RowFetch already reads up to `max_threads` blocks concurrently. Avoid a
277+ // cluster round trip for small limits, where all possible blocks fit in only a few
278+ // local I/O waves. The runtime metrics below let us tune this conservative guard.
279+ let distribute_row_fetch = table_indexes. len ( ) == 1
280+ && limit
281+ . limit
282+ . is_some_and ( |rows| rows > max_threads. saturating_mul ( 4 ) )
283+ && !self . ctx . get_cluster ( ) . is_empty ( )
284+ && Self :: contains_merge_exchange ( & plan) ;
223285
224286 let mut row_id_col_offsets = HashMap :: new ( ) ;
225287 for table_index in table_indexes. iter ( ) {
@@ -288,6 +350,22 @@ impl PhysicalPlanBuilder {
288350 ) )
289351 } ) ?;
290352
353+ if distribute_row_fetch {
354+ let shuffle_key =
355+ Self :: build_row_fetch_shuffle_key ( input_schema. as_ref ( ) , row_id_col_offset) ?;
356+ plan = PhysicalPlan :: new ( Exchange {
357+ input : plan,
358+ kind : FragmentKind :: RowFetch {
359+ row_id_col_offset,
360+ local_block_threshold : max_threads. saturating_mul ( 8 ) . max ( 128 ) ,
361+ } ,
362+ keys : vec ! [ shuffle_key] ,
363+ ignore_exchange : false ,
364+ allow_adjust_parallelism : true ,
365+ meta : PhysicalPlanMeta :: new ( "Exchange" ) ,
366+ } ) ;
367+ }
368+
291369 plan = PhysicalPlan :: new ( RowFetch {
292370 meta : PhysicalPlanMeta :: new ( "RowFetch" ) ,
293371 input : plan,
@@ -299,6 +377,33 @@ impl PhysicalPlanBuilder {
299377 enable_block_id_repartition : false ,
300378 stat_info : Some ( stat_info. clone ( ) ) ,
301379 } ) ;
380+
381+ if distribute_row_fetch {
382+ plan = PhysicalPlan :: new ( Exchange {
383+ input : plan,
384+ kind : FragmentKind :: Merge ,
385+ keys : vec ! [ ] ,
386+ ignore_exchange : false ,
387+ allow_adjust_parallelism : true ,
388+ meta : PhysicalPlanMeta :: new ( "Exchange" ) ,
389+ } ) ;
390+
391+ if let Some ( order_by) = order_by. clone ( )
392+ && !order_by. is_empty ( )
393+ {
394+ plan = PhysicalPlan :: new ( Sort {
395+ input : plan,
396+ order_by,
397+ limit : None ,
398+ step : SortStep :: Single ,
399+ pre_projection : None ,
400+ broadcast_id : None ,
401+ enable_fixed_rows : false ,
402+ stat_info : Some ( stat_info. clone ( ) ) ,
403+ meta : PhysicalPlanMeta :: new ( "Sort" ) ,
404+ } ) ;
405+ }
406+ }
302407 }
303408
304409 Ok ( plan)
0 commit comments