diff --git a/src/coordinator/prepare_dynamic_plan.rs b/src/coordinator/prepare_dynamic_plan.rs index b109cc2c..bbae6a97 100644 --- a/src/coordinator/prepare_dynamic_plan.rs +++ b/src/coordinator/prepare_dynamic_plan.rs @@ -3,7 +3,7 @@ use crate::coordinator::distributed::PreparedPlan; use crate::coordinator::query_coordinator::QueryCoordinator; use crate::distributed_planner::{ InjectNetworkBoundaryContext, NetworkBoundaryBuilderResult, ProducerHead, calculate_cost, - inject_network_boundaries, + inject_network_boundaries, validate_stage_plan, }; use crate::events::TaskCountAnnotation::{Desired, Maximum}; use crate::execution_plans::SamplerExec; @@ -75,6 +75,9 @@ pub(super) async fn prepare_dynamic_plan( input_stage.plan = nb_ctx .propagate_task_count_until_network_boundaries(&input_stage.plan, task_count)?; input_stage.tasks = task_count.as_usize(); + // The task count is now final; refuse to dispatch a stage whose plan cannot run + // correctly on that many tasks. + validate_stage_plan(&input_stage.plan, input_stage.tasks, nb_ctx.cfg)?; // In order to infer the compute the cost of the stage above this one, here a sampler // is injected to gather runtime statistics. input_stage.plan = ProducerHead::insert_sampler(input_stage.plan)?; diff --git a/src/distributed_planner/distributed_query_planner.rs b/src/distributed_planner/distributed_query_planner.rs index b2851536..9a02e317 100644 --- a/src/distributed_planner/distributed_query_planner.rs +++ b/src/distributed_planner/distributed_query_planner.rs @@ -4,9 +4,11 @@ use crate::distributed_planner::inject_network_boundaries::{ }; use crate::distributed_planner::insert_broadcast::insert_broadcast_execs; use crate::distributed_planner::insert_children_isolator_union::insert_children_isolator_unions; +use crate::distributed_planner::normalize_collect_joins::normalize_collect_joins; use crate::distributed_planner::partial_reduce_below_network_shuffles::partial_reduce_below_network_shuffles; use crate::distributed_planner::prepare_network_boundaries::prepare_network_boundaries; use crate::distributed_planner::push_fetch_into_network_coalesce::push_fetch_into_network_coalesce; +use crate::distributed_planner::validate_stages::validate_distributed_stages; use crate::events::{ScaleUpLeafNodeEvent, ScaleUpLeafNodeHandlers}; use crate::{DistributedConfig, DistributedExec, NetworkBoundaryExt}; use async_trait::async_trait; @@ -103,6 +105,7 @@ impl QueryPlanner for DistributedQueryPlanner { return Ok(plan); } let plan = push_fetch_into_network_coalesce(plan)?; + validate_distributed_stages(&plan, session_cfg)?; return Ok(Arc::new( DistributedExec::new(plan).with_metrics_collection(d_cfg.collect_metrics), )); @@ -110,12 +113,13 @@ impl QueryPlanner for DistributedQueryPlanner { let mut plan = Arc::clone(&original_plan); + let cfg = session_state.config_options(); + plan = normalize_collect_joins(plan, cfg)?; + if plan.output_partitioning().partition_count() > 1 { plan = Arc::new(CoalescePartitionsExec::new(plan)); } - let cfg = session_state.config_options(); - plan = insert_broadcast_execs(plan, cfg)?; plan = insert_children_isolator_unions(plan, cfg)?; @@ -137,6 +141,7 @@ impl QueryPlanner for DistributedQueryPlanner { let plan = partial_reduce_below_network_shuffles(plan, cfg)?; let plan = push_fetch_into_network_coalesce(plan)?; + validate_distributed_stages(&plan, session_cfg)?; Ok(Arc::new( DistributedExec::new(plan).with_metrics_collection(d_cfg.collect_metrics), @@ -351,11 +356,30 @@ mod tests { let physical_plan_ascii = TestPlanBuilder::default() .physical_plan_as_ascii(query, false) .await; - assert_snapshot!(physical_plan_ascii, @r" - HashJoinExec: mode=CollectLeft, join_type=Left, on=[(RainToday@1, RainToday@1)], projection=[MinTemp@0, MaxTemp@2] - CoalescePartitionsExec - DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet], [/testdata/weather/result-000001.parquet], [/testdata/weather/result-000002.parquet]]}, projection=[MinTemp, RainToday], file_type=parquet - DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet], [/testdata/weather/result-000001.parquet], [/testdata/weather/result-000002.parquet]]}, projection=[MaxTemp, RainToday], file_type=parquet, predicate=DynamicFilter [ empty ] + assert_snapshot!(physical_plan_ascii, @" + ┌───── DistributedExec + │ CoalescePartitionsExec + │ [Stage 3] => NetworkCoalesceExec: output_partitions=12, input_tasks=3 + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=3, partitions=4 + │ HashJoinExec: mode=Partitioned, join_type=Left, on=[(RainToday@1, RainToday@1)], projection=[MinTemp@0, MaxTemp@2] + │ [Stage 1] => NetworkShuffleExec: output_partitions=4, input_tasks=3 + │ [Stage 2] => NetworkShuffleExec: output_partitions=4, input_tasks=3 + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=3, partitions=12 + │ RepartitionExec: partitioning=Hash([RainToday@1], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000000.parquet:.., /testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MinTemp, RainToday], file_type=parquet + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MinTemp, RainToday], file_type=parquet + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:.., /testdata/weather/result-000002.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MinTemp, RainToday], file_type=parquet + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=3, partitions=12 + │ RepartitionExec: partitioning=Hash([RainToday@1], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000000.parquet:.., /testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MaxTemp, RainToday], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MaxTemp, RainToday], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:.., /testdata/weather/result-000002.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MaxTemp, RainToday], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── "); } @@ -387,41 +411,48 @@ mod tests { let physical_plan_ascii = TestPlanBuilder::default() .physical_plan_as_ascii(query, false) .await; - assert_snapshot!(physical_plan_ascii, @r" + assert_snapshot!(physical_plan_ascii, @" ┌───── DistributedExec │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=Left, on=[(RainTomorrow@1, RainTomorrow@1)], projection=[MinTemp@0, MaxTemp@2] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkCoalesceExec: output_partitions=8, input_tasks=2 - │ ProjectionExec: expr=[avg(weather.MaxTemp)@1 as MaxTemp, RainTomorrow@0 as RainTomorrow] - │ AggregateExec: mode=FinalPartitioned, gby=[RainTomorrow@0 as RainTomorrow], aggr=[avg(weather.MaxTemp)] - │ [Stage 3] => NetworkShuffleExec: output_partitions=4, input_tasks=3 + │ [Stage 5] => NetworkCoalesceExec: output_partitions=8, input_tasks=2 └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=2, partitions=4 - │ ProjectionExec: expr=[avg(weather.MinTemp)@1 as MinTemp, RainTomorrow@0 as RainTomorrow] - │ AggregateExec: mode=FinalPartitioned, gby=[RainTomorrow@0 as RainTomorrow], aggr=[avg(weather.MinTemp)] - │ [Stage 1] => NetworkShuffleExec: output_partitions=4, input_tasks=3 + ┌───── Stage 5 ── tasks=2, partitions=4 + │ HashJoinExec: mode=Partitioned, join_type=Left, on=[(RainTomorrow@1, RainTomorrow@1)], projection=[MinTemp@0, MaxTemp@2] + │ [Stage 2] => NetworkShuffleExec: output_partitions=4, input_tasks=2 + │ [Stage 4] => NetworkShuffleExec: output_partitions=4, input_tasks=2 └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=3, partitions=8 - │ RepartitionExec: partitioning=Hash([RainTomorrow@0], 8), input_partitions=4 - │ AggregateExec: mode=Partial, gby=[RainTomorrow@1 as RainTomorrow], aggr=[avg(weather.MinTemp)] - │ FilterExec: RainToday@1 = yes, projection=[MinTemp@0, RainTomorrow@2] - │ RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=3 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000000.parquet:.., /testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MinTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = yes, pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= yes AND yes <= RainToday_max@1, required_guarantees=[RainToday in (yes)] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MinTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = yes, pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= yes AND yes <= RainToday_max@1, required_guarantees=[RainToday in (yes)] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:.., /testdata/weather/result-000002.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MinTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = yes, pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= yes AND yes <= RainToday_max@1, required_guarantees=[RainToday in (yes)] + ┌───── Stage 2 ── tasks=2, partitions=8 + │ RepartitionExec: partitioning=Hash([RainTomorrow@1], 8), input_partitions=4 + │ ProjectionExec: expr=[avg(weather.MinTemp)@1 as MinTemp, RainTomorrow@0 as RainTomorrow] + │ AggregateExec: mode=FinalPartitioned, gby=[RainTomorrow@0 as RainTomorrow], aggr=[avg(weather.MinTemp)] + │ [Stage 1] => NetworkShuffleExec: output_partitions=4, input_tasks=3 └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=3, partitions=4 - │ RepartitionExec: partitioning=Hash([RainTomorrow@0], 4), input_partitions=4 - │ AggregateExec: mode=Partial, gby=[RainTomorrow@1 as RainTomorrow], aggr=[avg(weather.MaxTemp)] - │ FilterExec: RainToday@1 = no, projection=[MaxTemp@0, RainTomorrow@2] - │ RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=3 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000000.parquet:.., /testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MaxTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = no AND DynamicFilter [ empty ], pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= no AND no <= RainToday_max@1, required_guarantees=[RainToday in (no)] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MaxTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = no AND DynamicFilter [ empty ], pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= no AND no <= RainToday_max@1, required_guarantees=[RainToday in (no)] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:.., /testdata/weather/result-000002.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MaxTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = no AND DynamicFilter [ empty ], pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= no AND no <= RainToday_max@1, required_guarantees=[RainToday in (no)] - └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=3, partitions=8 + │ RepartitionExec: partitioning=Hash([RainTomorrow@0], 8), input_partitions=4 + │ AggregateExec: mode=Partial, gby=[RainTomorrow@1 as RainTomorrow], aggr=[avg(weather.MinTemp)] + │ FilterExec: RainToday@1 = yes, projection=[MinTemp@0, RainTomorrow@2] + │ RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000000.parquet:.., /testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MinTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = yes, pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= yes AND yes <= RainToday_max@1, required_guarantees=[RainToday in (yes)] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MinTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = yes, pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= yes AND yes <= RainToday_max@1, required_guarantees=[RainToday in (yes)] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:.., /testdata/weather/result-000002.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MinTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = yes, pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= yes AND yes <= RainToday_max@1, required_guarantees=[RainToday in (yes)] + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=2, partitions=8 + │ RepartitionExec: partitioning=Hash([RainTomorrow@1], 8), input_partitions=4 + │ ProjectionExec: expr=[avg(weather.MaxTemp)@1 as MaxTemp, RainTomorrow@0 as RainTomorrow] + │ AggregateExec: mode=FinalPartitioned, gby=[RainTomorrow@0 as RainTomorrow], aggr=[avg(weather.MaxTemp)] + │ [Stage 3] => NetworkShuffleExec: output_partitions=4, input_tasks=3 + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=3, partitions=8 + │ RepartitionExec: partitioning=Hash([RainTomorrow@0], 8), input_partitions=4 + │ AggregateExec: mode=Partial, gby=[RainTomorrow@1 as RainTomorrow], aggr=[avg(weather.MaxTemp)] + │ FilterExec: RainToday@1 = no, projection=[MaxTemp@0, RainTomorrow@2] + │ RepartitionExec: partitioning=RoundRobinBatch(4), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000000.parquet:.., /testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MaxTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = no AND DynamicFilter [ empty ], pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= no AND no <= RainToday_max@1, required_guarantees=[RainToday in (no)] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MaxTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = no AND DynamicFilter [ empty ], pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= no AND no <= RainToday_max@1, required_guarantees=[RainToday in (no)] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet:..], [/testdata/weather/result-000001.parquet:.., /testdata/weather/result-000002.parquet:..], [/testdata/weather/result-000002.parquet:..]]}, projection=[MaxTemp, RainToday, RainTomorrow], file_type=parquet, predicate=RainToday@19 = no AND DynamicFilter [ empty ], pruning_predicate=RainToday_null_count@2 != row_count@3 AND RainToday_min@0 <= no AND no <= RainToday_max@1, required_guarantees=[RainToday in (no)] + └────────────────────────────────────────────────── "); } diff --git a/src/distributed_planner/inject_network_boundaries.rs b/src/distributed_planner/inject_network_boundaries.rs index 6e433ec6..eb7d36bb 100644 --- a/src/distributed_planner/inject_network_boundaries.rs +++ b/src/distributed_planner/inject_network_boundaries.rs @@ -12,11 +12,13 @@ use crate::{ }; use async_trait::async_trait; use datafusion::common::tree_node::{TreeNode, TreeNodeRecursion}; -use datafusion::common::{HashMap, Result, plan_err}; +use datafusion::common::{HashMap, JoinType, Result, plan_err}; use datafusion::physical_expr::Partitioning; use datafusion::physical_plan::coalesce_partitions::CoalescePartitionsExec; use datafusion::physical_plan::execution_plan::CardinalityEffect; -use datafusion::physical_plan::joins::{HashJoinExec, PartitionMode}; +use datafusion::physical_plan::joins::{ + CrossJoinExec, HashJoinExec, NestedLoopJoinExec, PartitionMode, +}; use datafusion::physical_plan::repartition::RepartitionExec; use datafusion::physical_plan::sorts::sort_preserving_merge::SortPreservingMergeExec; use datafusion::physical_plan::{ExecutionPlan, PlanProperties}; @@ -159,7 +161,7 @@ pub(crate) async fn inject_network_boundaries( pub(crate) struct InjectNetworkBoundaryContext<'a> { pub(crate) d_cfg: &'a DistributedConfig, - cfg: &'a SessionConfig, + pub(crate) cfg: &'a SessionConfig, worker_resolver: Arc, nb_builder: &'a (dyn NetworkBoundaryBuilder + Send + Sync), task_counts: &'a Mutex>, @@ -273,10 +275,28 @@ async fn _inject_network_boundaries( task_count = Desired(count); } else if let Some(node) = plan.downcast_ref::() && node.mode == PartitionMode::CollectLeft - && !broadcast_joins_enabled + && (!broadcast_joins_enabled || node.null_aware) + { + // A CollectLeft join collects its entire build side in every task, so it can only run in + // a multi-task stage when [insert_broadcast_execs] broadcast the build side. That is not + // possible when broadcast joins are disabled, nor for null-aware anti joins, whose + // NULL-existence checks live in process-local shared state that cannot span tasks in any + // orientation. Other build-side-emitting join types were already rewritten to Partitioned + // by [normalize_collect_joins], so they never reach this arm. + task_count = Maximum(1); + } else if let Some(node) = plan.downcast_ref::() + && (!broadcast_joins_enabled || node.join_type() == &JoinType::Full) { - // Only distribute CollectLeft HashJoins after we broadcast more intelligently or when it - // is explicitly enabled. + // A NestedLoopJoin always collects its entire left side in every task, so it also needs + // its build side broadcast to run in a multi-task stage. Full joins emit unmatched rows + // from both sides, which needs global match knowledge that cannot span tasks, so they + // always run in a single task. Other build-side-emitting join types were already swapped + // to probe-side-emitting ones by [normalize_collect_joins]. + task_count = Maximum(1); + } else if plan.is::() && !broadcast_joins_enabled { + // A CrossJoin also collects its entire left side in every task. It is always safe to + // broadcast (it emits only pair rows), so it is only restricted to a single task when + // broadcasts are unavailable. task_count = Maximum(1); } else { // The task count for this plan is decided by the biggest task count from the children; unless @@ -632,6 +652,7 @@ mod tests { use super::*; use crate::distributed_planner::insert_broadcast::insert_broadcast_execs; use crate::distributed_planner::insert_children_isolator_union::insert_children_isolator_unions; + use crate::distributed_planner::normalize_collect_joins::normalize_collect_joins; use crate::test_utils::plans::{TestPlanBuilder, build_side_one_desired_task_count_handler}; use crate::{DesiredTaskCountEvent, DesiredTaskCountEventResponse, assert_snapshot}; use datafusion::physical_plan::coalesce_partitions::CoalescePartitionsExec; @@ -713,11 +734,14 @@ mod tests { .distributed_planner(false) .broadcast_joins(false); let annotated = annotate_test_plan(test_plan_builder, query).await; - assert_snapshot!(annotated, @r" - HashJoinExec: task_count=Maximum(1) - CoalescePartitionsExec: task_count=Maximum(1) - DistributedLeafExec: task_count=Maximum(1) - DistributedLeafExec: task_count=Maximum(1) + assert_snapshot!(annotated, @" + HashJoinExec: task_count=Desired(4) + NetworkShuffleExec: task_count=Desired(4) + RepartitionExec: task_count=Desired(4) + DistributedLeafExec: task_count=Desired(4) + NetworkShuffleExec: task_count=Desired(4) + RepartitionExec: task_count=Desired(4) + DistributedLeafExec: task_count=Desired(4) ") } @@ -753,10 +777,20 @@ mod tests { .distributed_planner(false) .broadcast_joins(false); let annotated = annotate_test_plan(test_plan_builder, query).await; - assert_snapshot!(annotated, @r" - HashJoinExec: task_count=Maximum(1) - CoalescePartitionsExec: task_count=Maximum(1) - NetworkCoalesceExec: task_count=Maximum(1) + assert_snapshot!(annotated, @" + HashJoinExec: task_count=Desired(2) + NetworkShuffleExec: task_count=Desired(2) + RepartitionExec: task_count=Desired(2) + ProjectionExec: task_count=Desired(2) + AggregateExec: task_count=Desired(2) + NetworkShuffleExec: task_count=Desired(2) + RepartitionExec: task_count=Desired(4) + AggregateExec: task_count=Desired(4) + FilterExec: task_count=Desired(4) + RepartitionExec: task_count=Desired(4) + DistributedLeafExec: task_count=Desired(4) + NetworkShuffleExec: task_count=Desired(2) + RepartitionExec: task_count=Desired(2) ProjectionExec: task_count=Desired(2) AggregateExec: task_count=Desired(2) NetworkShuffleExec: task_count=Desired(2) @@ -765,14 +799,6 @@ mod tests { FilterExec: task_count=Desired(4) RepartitionExec: task_count=Desired(4) DistributedLeafExec: task_count=Desired(4) - ProjectionExec: task_count=Maximum(1) - AggregateExec: task_count=Maximum(1) - NetworkShuffleExec: task_count=Maximum(1) - RepartitionExec: task_count=Desired(4) - AggregateExec: task_count=Desired(4) - FilterExec: task_count=Desired(4) - RepartitionExec: task_count=Desired(4) - DistributedLeafExec: task_count=Desired(4) ") } @@ -1085,6 +1111,32 @@ mod tests { "); } + #[tokio::test] + async fn test_nested_loop_inner_join_broadcast() { + // Inner joins emit only probe-driven rows, so the left side can be broadcast and + // the join can run in a multi-task stage. + let query = r#" + SELECT a."MinTemp", b."MaxTemp" + FROM weather a INNER JOIN weather b + ON a."MinTemp" < b."MaxTemp" + "#; + let test_plan_builder = TestPlanBuilder::new() + .target_partitions(4) + .num_workers(4) + // annotate_test_plan wants this as false so its s a single node plan + .distributed_planner(false) + .broadcast_joins(true); + let annotated = annotate_test_plan(test_plan_builder, query).await; + assert_snapshot!(annotated, @" + NestedLoopJoinExec: task_count=Desired(4) + CoalescePartitionsExec: task_count=Desired(4) + NetworkBroadcastExec: task_count=Desired(4) + BroadcastExec: task_count=Desired(4) + DistributedLeafExec: task_count=Desired(4) + DistributedLeafExec: task_count=Desired(4) + "); + } + #[tokio::test] async fn test_broadcast_disabled_default() { let query = r#" @@ -1210,6 +1262,8 @@ mod tests { let plan = test_plan.physical_plan(query).await; let session_config = test_plan.get_ctx().copied_config(); + let plan = normalize_collect_joins(plan, session_config.options()) + .expect("failed to normalize collect joins"); let plan = insert_broadcast_execs(plan, session_config.options()) .expect("failed to insert broadcasts"); let plan = insert_children_isolator_unions(plan, session_config.options()) diff --git a/src/distributed_planner/insert_broadcast.rs b/src/distributed_planner/insert_broadcast.rs index 33381936..64e9a3e4 100644 --- a/src/distributed_planner/insert_broadcast.rs +++ b/src/distributed_planner/insert_broadcast.rs @@ -165,7 +165,7 @@ fn can_broadcast_left_input(plan: &dyn ExecutionPlan) -> bool { plan.downcast_ref::().is_some() } -fn is_left_broadcast_safe(join_type: &JoinType) -> bool { +pub(super) fn is_left_broadcast_safe(join_type: &JoinType) -> bool { matches!( join_type, JoinType::Inner diff --git a/src/distributed_planner/mod.rs b/src/distributed_planner/mod.rs index 57975991..35d79bc8 100644 --- a/src/distributed_planner/mod.rs +++ b/src/distributed_planner/mod.rs @@ -4,11 +4,13 @@ mod inject_network_boundaries; mod insert_broadcast; mod insert_children_isolator_union; mod network_boundary; +mod normalize_collect_joins; mod partial_reduce_below_network_shuffles; mod prepare_network_boundaries; mod push_fetch_into_network_coalesce; mod session_state_builder_ext; mod statistics; +mod validate_stages; pub use distributed_config::DistributedConfig; pub(crate) use inject_network_boundaries::{ @@ -18,3 +20,4 @@ pub(crate) use network_boundary::ProducerHead; pub use network_boundary::{NetworkBoundary, NetworkBoundaryExt}; pub use session_state_builder_ext::SessionStateBuilderExt; pub(crate) use statistics::calculate_cost; +pub(crate) use validate_stages::validate_stage_plan; diff --git a/src/distributed_planner/normalize_collect_joins.rs b/src/distributed_planner/normalize_collect_joins.rs new file mode 100644 index 00000000..0f7bc39e --- /dev/null +++ b/src/distributed_planner/normalize_collect_joins.rs @@ -0,0 +1,215 @@ +use std::sync::Arc; + +use datafusion::common::JoinType; +use datafusion::common::tree_node::{Transformed, TreeNode}; +use datafusion::config::ConfigOptions; +use datafusion::error::DataFusionError; +use datafusion::physical_expr::Partitioning; +use datafusion::physical_plan::ExecutionPlan; +use datafusion::physical_plan::coalesce_partitions::CoalescePartitionsExec; +use datafusion::physical_plan::joins::{HashJoinExec, NestedLoopJoinExec, PartitionMode}; +use datafusion::physical_plan::repartition::RepartitionExec; + +use super::DistributedConfig; +use super::insert_broadcast::is_left_broadcast_safe; + +/// Rewrites joins that would otherwise be restricted to a single task into shapes that +/// distribute correctly. +/// +/// [insert_broadcast_execs] can only broadcast the build side of joins whose join type never +/// emits build-side rows (see [is_left_broadcast_safe]): a broadcast build side is replicated +/// into every task, so a join type that emits build-side rows would emit them once per task. +/// Without a broadcast, a multi-task stage gives every task only a slice of the collected build +/// side, which silently loses rows. This pass rewrites the affected joins instead of leaving +/// them to run in a single task: +/// +/// - CollectLeft [HashJoinExec]s with a build-side-emitting join type become +/// [PartitionMode::Partitioned], hash-repartitioning both sides on the join keys. Every +/// matching row pair then meets in exactly one partition, owned by exactly one task, so each +/// build-side row is emitted exactly once with complete match information. +/// - [NestedLoopJoinExec]s with a build-side-emitting join type are swapped (Left becomes +/// Right, LeftSemi becomes RightSemi, and so on), so the emitting side becomes the +/// partitioned probe side and the other side can be broadcast as usual. There is no +/// partitioned fallback for a NestedLoopJoin: its predicate is arbitrary, so no partitioning +/// can co-locate matching rows. +/// +/// Two shapes have no distributed rewrite and are left untouched for +/// [inject_network_boundaries] to cap at a single task: +/// +/// - Null-aware anti joins: their NULL-existence checks require global knowledge held in +/// process-local shared state, which cannot span tasks in any orientation. +/// - Full joins: they emit unmatched rows from both sides, so they need global match knowledge +/// on both sides at once. +/// +/// [insert_broadcast_execs]: super::insert_broadcast::insert_broadcast_execs +/// [inject_network_boundaries]: super::inject_network_boundaries::inject_network_boundaries +pub(super) fn normalize_collect_joins( + plan: Arc, + cfg: &ConfigOptions, +) -> Result, DataFusionError> { + let d_cfg = DistributedConfig::from_config_options(cfg)?; + let target_partitions = cfg.execution.target_partitions; + + plan.transform_down(|node| { + if let Some(join) = node.downcast_ref::() + && join.mode == PartitionMode::CollectLeft + && !is_left_broadcast_safe(join.join_type()) + && join.join_type() != &JoinType::Full + && !join.null_aware + { + return Ok(Transformed::yes(collect_left_to_partitioned( + join, + target_partitions, + )?)); + } + if let Some(join) = node.downcast_ref::() + // Swapping only helps when the resulting probe-side-emitting join can actually be + // broadcast; without broadcasts the join runs in a single task either way. + && d_cfg.broadcast_joins + && !is_left_broadcast_safe(join.join_type()) + && join.join_type() != &JoinType::Full + { + // The build side's CoalescePartitionsExec only exists to satisfy the single-partition + // requirement of the *current* orientation. After the swap that side becomes the + // partitioned probe side, so strip it or it would serialize the probe; + // [insert_broadcast_execs] re-coalesces the new build side when it broadcasts it. + let swapped = match join.left().downcast_ref::() { + Some(coalesce) => Arc::clone(&node) + .with_new_children(vec![ + Arc::clone(coalesce.input()), + Arc::clone(join.right()), + ])? + .downcast_ref::() + .expect("with_new_children changed the node type") + .swap_inputs()?, + None => join.swap_inputs()?, + }; + return Ok(Transformed::yes(swapped)); + } + Ok(Transformed::no(node)) + }) + .map(|transformed| transformed.data) +} + +/// Rebuilds a CollectLeft [HashJoinExec] as a [PartitionMode::Partitioned] one, hash-partitioning +/// both inputs on the join keys. The build side's [CoalescePartitionsExec] (the artifact of +/// CollectLeft's single-partition requirement) is stripped, as the hash repartition replaces it. +fn collect_left_to_partitioned( + join: &HashJoinExec, + target_partitions: usize, +) -> Result, DataFusionError> { + let (left_keys, right_keys): (Vec<_>, Vec<_>) = join + .on() + .iter() + .map(|(l, r)| (Arc::clone(l), Arc::clone(r))) + .unzip(); + + let build_input = join + .left() + .downcast_ref::() + .map_or_else(|| Arc::clone(join.left()), |c| Arc::clone(c.input())); + + let left = Arc::new(RepartitionExec::try_new( + build_input, + Partitioning::Hash(left_keys, target_partitions), + )?); + let right = Arc::new(RepartitionExec::try_new( + Arc::clone(join.right()), + Partitioning::Hash(right_keys, target_partitions), + )?); + + Ok(Arc::new(HashJoinExec::try_new( + left, + right, + join.on().to_vec(), + join.filter().cloned(), + join.join_type(), + join.projection.as_ref().map(|p| p.to_vec()), + PartitionMode::Partitioned, + join.null_equality(), + join.null_aware, + )?)) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::assert_snapshot; + use crate::test_utils::plans::TestPlanBuilder; + use datafusion::physical_plan::displayable; + + async fn sql_to_normalized_plan(query: &str, broadcast_enabled: bool) -> String { + let test_plan = TestPlanBuilder::new() + .target_partitions(3) + .broadcast_joins(broadcast_enabled) + .build() + .await; + let ctx = test_plan.get_ctx(); + let plan = test_plan.physical_plan(query).await; + let plan = normalize_collect_joins(plan, ctx.state_ref().read().config_options().as_ref()) + .expect("failed to normalize collect joins"); + format!("{}", displayable(plan.as_ref()).indent(true)) + } + + #[tokio::test] + async fn test_left_hash_join_converted_to_partitioned() { + let query = r#" + SELECT a."MinTemp", b."MaxTemp" + FROM weather a LEFT JOIN weather b + ON a."RainToday" = b."RainToday" + "#; + let plan = sql_to_normalized_plan(query, true).await; + assert!(plan.contains("HashJoinExec: mode=Partitioned, join_type=Left")); + assert_snapshot!(plan); + } + + #[tokio::test] + async fn test_nested_loop_left_join_swapped() { + let query = r#" + SELECT a."MinTemp", b."MaxTemp" + FROM weather a LEFT JOIN weather b + ON a."MinTemp" < b."MaxTemp" + "#; + let plan = sql_to_normalized_plan(query, true).await; + assert!(plan.contains("NestedLoopJoinExec: join_type=Right")); + assert_snapshot!(plan); + } + + #[tokio::test] + async fn test_nested_loop_full_join_untouched() { + let query = r#" + SELECT a."MinTemp", b."MaxTemp" + FROM weather a FULL JOIN weather b + ON a."MinTemp" < b."MaxTemp" + "#; + let plan = sql_to_normalized_plan(query, true).await; + assert!(plan.contains("NestedLoopJoinExec: join_type=Full")); + assert!(!plan.contains("RepartitionExec: partitioning=Hash")); + } + + #[tokio::test] + async fn test_inner_collect_left_join_untouched() { + // Inner joins are broadcast-safe, so they keep their CollectLeft shape and get a + // broadcast from insert_broadcast_execs instead. + let query = r#" + SELECT a."MinTemp", b."MaxTemp" + FROM weather a INNER JOIN weather b + ON a."RainToday" = b."RainToday" + "#; + let plan = sql_to_normalized_plan(query, true).await; + assert!(plan.contains("HashJoinExec: mode=CollectLeft, join_type=Inner")); + } + + #[tokio::test] + async fn test_nested_loop_left_join_untouched_without_broadcasts() { + // Without broadcast joins the swapped join could not be broadcast either, so the + // rewrite is skipped and the join runs in a single task. + let query = r#" + SELECT a."MinTemp", b."MaxTemp" + FROM weather a LEFT JOIN weather b + ON a."MinTemp" < b."MaxTemp" + "#; + let plan = sql_to_normalized_plan(query, false).await; + assert!(plan.contains("NestedLoopJoinExec: join_type=Left")); + } +} diff --git a/src/distributed_planner/snapshots/datafusion_distributed__distributed_planner__normalize_collect_joins__tests__left_hash_join_converted_to_partitioned.snap b/src/distributed_planner/snapshots/datafusion_distributed__distributed_planner__normalize_collect_joins__tests__left_hash_join_converted_to_partitioned.snap new file mode 100644 index 00000000..b0169073 --- /dev/null +++ b/src/distributed_planner/snapshots/datafusion_distributed__distributed_planner__normalize_collect_joins__tests__left_hash_join_converted_to_partitioned.snap @@ -0,0 +1,9 @@ +--- +source: src/distributed_planner/normalize_collect_joins.rs +expression: plan +--- +HashJoinExec: mode=Partitioned, join_type=Left, on=[(RainToday@1, RainToday@1)], projection=[MinTemp@0, MaxTemp@2] + RepartitionExec: partitioning=Hash([RainToday@1], 3), input_partitions=3 + DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet], [/testdata/weather/result-000001.parquet], [/testdata/weather/result-000002.parquet]]}, projection=[MinTemp, RainToday], file_type=parquet + RepartitionExec: partitioning=Hash([RainToday@1], 3), input_partitions=3 + DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet], [/testdata/weather/result-000001.parquet], [/testdata/weather/result-000002.parquet]]}, projection=[MaxTemp, RainToday], file_type=parquet, predicate=DynamicFilter [ empty ] diff --git a/src/distributed_planner/snapshots/datafusion_distributed__distributed_planner__normalize_collect_joins__tests__nested_loop_left_join_swapped.snap b/src/distributed_planner/snapshots/datafusion_distributed__distributed_planner__normalize_collect_joins__tests__nested_loop_left_join_swapped.snap new file mode 100644 index 00000000..37c21e6e --- /dev/null +++ b/src/distributed_planner/snapshots/datafusion_distributed__distributed_planner__normalize_collect_joins__tests__nested_loop_left_join_swapped.snap @@ -0,0 +1,8 @@ +--- +source: src/distributed_planner/normalize_collect_joins.rs +expression: plan +--- +ProjectionExec: expr=[MinTemp@1 as MinTemp, MaxTemp@0 as MaxTemp] + NestedLoopJoinExec: join_type=Right, filter=MinTemp@0 < MaxTemp@1 + DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet], [/testdata/weather/result-000001.parquet], [/testdata/weather/result-000002.parquet]]}, projection=[MaxTemp], file_type=parquet + DataSourceExec: file_groups={3 groups: [[/testdata/weather/result-000000.parquet], [/testdata/weather/result-000001.parquet], [/testdata/weather/result-000002.parquet]]}, projection=[MinTemp], file_type=parquet diff --git a/src/distributed_planner/validate_stages.rs b/src/distributed_planner/validate_stages.rs new file mode 100644 index 00000000..f46f8086 --- /dev/null +++ b/src/distributed_planner/validate_stages.rs @@ -0,0 +1,639 @@ +//! Validates the fundamental invariant of stage replication: for every stage, +//! executing its plan once per task over the per-task input assignment and unioning the +//! outputs must be equivalent to executing it once over all the data. +//! +//! DataFusion's optimizer discharges each operator's `required_input_distribution()` +//! obligations *process-locally* (a `SinglePartition` requirement is satisfied by a +//! `CoalescePartitionsExec`, a `HashPartitioned` one by a `RepartitionExec`). Replicating the +//! plan across tasks silently reinterprets "all the data" as "this task's slice", invalidating +//! those discharged obligations. Only the exchange operators — the `Network*Exec` boundaries — +//! restore properties globally: +//! +//! - `NetworkShuffleExec` → globally hash-partitioned (equal keys co-locate cluster-wide) +//! - `NetworkBroadcastExec` → a complete, identical copy in every task +//! - `NetworkCoalesceExec` → a global single partition, via a single consumer task +//! +//! The validator classifies every stage-local subtree bottom-up as either [Replicated] +//! (every task materializes the identical complete dataset) or [Partitioned] (every task +//! materializes a task-specific slice whose union is the whole), and enforces two obligations +//! along the way: +//! +//! (A) every declared input-distribution requirement must hold *cluster-globally*: +//! `SinglePartition` may only be satisfied by a replicated subtree, and +//! `HashPartitioned` only by a claim that (1) semantically satisfies the required +//! expressions — checked with [Partitioning::satisfaction] against the child's claimed +//! output partitioning and equivalence classes, exactly as DataFusion's own +//! EnforceDistribution/SanityCheckPlan do process-locally — and (2) is globally true, +//! i.e. established by a global exchange rather than a stage-local repartition; +//! (B) replicated data may only feed operators that never *emit* rows driven by it — +//! N task instances would emit such rows N times, and the machinery that deduplicates +//! them in a single process (e.g. the hash join's shared visited bitmap) does not exist +//! across tasks. This is the one fact not derivable from any DataFusion API; see +//! [emits_rows_driven_by]. +//! +//! Ordering is a known gap: output-ordering claims weaken from global to task-local exactly +//! like distribution claims, but this validator does not model them. + +use std::sync::Arc; + +use datafusion::common::{Result, plan_err}; +use datafusion::physical_expr::Partitioning; +use datafusion::physical_plan::joins::{CrossJoinExec, HashJoinExec, NestedLoopJoinExec}; +use datafusion::physical_plan::repartition::RepartitionExec; +use datafusion::physical_plan::{Distribution, ExecutionPlan, ExecutionPlanProperties}; + +use datafusion::prelude::SessionConfig; + +use crate::execution_plans::{ChildrenIsolatorUnionExec, DistributedLeafExec}; +use crate::stage::{Stage, find_all_stages}; +use crate::{NetworkBoundaryExt, NetworkBroadcastExec, NetworkShuffleExec}; + +use super::insert_broadcast::is_left_broadcast_safe; + +/// How a subtree's data is laid out across the tasks of its stage. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum DataFlow { + /// Every task materializes the identical, complete dataset. + Replicated, + /// Every task materializes a task-specific subset; the union across tasks is the whole + /// dataset. `claims_are_global` records provenance: whether the partitioning this + /// subtree *claims* in its `PlanProperties` (e.g. `Partitioning::Hash`) was established + /// by a global exchange (or exchange-aligned storage) and merely preserved since — as + /// opposed to being minted task-locally by a stage-local `RepartitionExec`, where the + /// same claim only holds within each task's slice of the data. + Partitioned { claims_are_global: bool }, +} + +/// Validates every stage embedded in a fully planned distributed plan. +pub(crate) fn validate_distributed_stages( + plan: &Arc, + session_cfg: &SessionConfig, +) -> Result<()> { + for stage in find_all_stages(plan) { + if let Stage::Local(stage) = stage { + validate_stage_plan(&stage.plan, stage.tasks, session_cfg)?; + } + } + Ok(()) +} + +/// Validates a single stage's plan against its task count. Single-task stages are trivially +/// correct: one instance sees all the data, exactly as DataFusion's optimizer assumed. +/// +/// The `estimator` is the same [TaskEstimator] machinery the planner used to decide leaf task +/// counts; the validator consults it to tell task-varying leaves from replicated ones. +pub(crate) fn validate_stage_plan( + plan: &Arc, + tasks: usize, + session_cfg: &SessionConfig, +) -> Result<()> { + if tasks <= 1 { + return Ok(()); + } + match classify(plan, tasks, session_cfg)? { + DataFlow::Partitioned { .. } => Ok(()), + DataFlow::Replicated => plan_err!( + "stage runs {tasks} tasks but its plan is fully replicated: every task would \ + produce the identical output and the stage would emit {tasks} copies of it" + ), + } +} + +/// Classifies `node`'s output as [DataFlow::Replicated] or [DataFlow::Partitioned] and +/// enforces obligations (A) and (B) for its inputs. Recursion stops at network boundaries: +/// their subtrees belong to child stages, which are validated against their own task counts. +fn classify( + node: &Arc, + tasks: usize, + session_cfg: &SessionConfig, +) -> Result { + // Exchange operators re-establish global properties. + if node.is::() { + return Ok(DataFlow::Replicated); + } + if node.is::() { + return Ok(DataFlow::Partitioned { + claims_are_global: true, + }); + } + if node.is_network_boundary() { + // NetworkCoalesceExec (or a future boundary type): gathers all partitions into a + // single consumer task, so it must never appear in a multi-task stage. + return plan_err!( + "stage runs {tasks} tasks but contains {}, which requires a single-task \ + consumer stage", + node.name() + ); + } + // A DistributedLeafExec resolves to a different slice of the underlying source in every + // task. (Its per-task variants are children in the plan tree, so check before the leaf + // case below.) If the scan preserves a hash partitioning from the storage layout + // (hive-style pre-partitioned files with `preserve_file_partitions`), the per-task + // slicing follows those same partitions, so equal keys still co-locate cluster-wide. + if node.is::() { + let claims_are_global = matches!(node.output_partitioning(), Partitioning::Hash(..)); + return Ok(DataFlow::Partitioned { claims_are_global }); + } + // A ChildrenIsolatorUnionExec divides the stage's tasks among its children: child `i` + // executes only in the tasks its `task_idx_map` assigns to it. Each child subtree must + // therefore be validated against its own effective task count, not the stage's. A child + // allotted a single task behaves like a single-task stage — trivially correct, including + // any NetworkCoalesceExec it contains. + if let Some(union) = node.downcast_ref::() { + for (child_idx, child) in union.children.iter().enumerate() { + let child_tasks = union + .task_idx_map + .iter() + .filter(|entries| entries.iter().any(|(child, _)| *child == child_idx)) + .count(); + if child_tasks > 1 && classify(child, child_tasks, session_cfg)? == DataFlow::Replicated + { + return plan_err!( + "input {child_idx} of {} is replicated but allotted {child_tasks} tasks; \ + each task would emit an identical copy of its data", + node.name() + ); + } + } + // Children occupy disjoint task allotments, so across the stage's tasks the union + // emits each child's data exactly once. + return Ok(DataFlow::Partitioned { + claims_are_global: false, + }); + } + let children = node.children(); + if children.is_empty() { + // A leaf that some TaskEstimator knows how to scale is task-varying: each task + // executes it over its own slice or work assignment (this mirrors how + // `inject_network_boundaries` decides leaf task counts, and covers custom sources + // like work-unit-feed leaves). Any other leaf (in-memory table, literal values) is + // embedded verbatim in every task's serialized plan: identical, complete data. + // NOTE: a volatile leaf (e.g. one backed by a random or time-dependent source) + // would break the replication assumption; nothing in the ExecutionPlan API exposes + // that. + let ev = crate::events::DesiredTaskCountEvent { + plan: node, + session_config: session_cfg, + }; + let is_task_varying = crate::events::DesiredTaskCountHandlers::handle(ev).is_some(); + return Ok(if is_task_varying { + DataFlow::Partitioned { + claims_are_global: matches!(node.output_partitioning(), Partitioning::Hash(..)), + } + } else { + DataFlow::Replicated + }); + } + + let child_flows = children + .iter() + .map(|child| classify(child, tasks, session_cfg)) + .collect::>>()?; + + // Obligation (A): declared input-distribution requirements must hold cluster-globally. + let requirements = node.required_input_distribution(); + for (idx, ((child, flow), requirement)) in children + .iter() + .zip(&child_flows) + .zip(&requirements) + .enumerate() + { + match requirement { + Distribution::UnspecifiedDistribution => {} + Distribution::SinglePartition => { + if let DataFlow::Partitioned { .. } = flow { + return plan_err!( + "{} requires a single partition from its input {idx} ({}), but in a \ + {tasks}-task stage that input only delivers the task's own slice of \ + the data; each task would silently compute on partial data. The \ + input must be replicated (broadcast) or the stage must run in a \ + single task", + node.name(), + child.name() + ); + } + } + Distribution::HashPartitioned(_) => { + // `Replicated` inputs pass both checks below: every task computes over the + // complete data, and whether the resulting duplication is legal is decided + // where it mixes into partitioned flow, or at the stage root. + if let DataFlow::Partitioned { claims_are_global } = flow { + // Semantic check, delegated to DataFusion: does the child's claimed + // output partitioning satisfy the required expressions? Equivalence + // classes make renamed keys pass; dropped or wrong keys fail. Subset + // satisfaction — partitioned on a subset of the required keys — still + // co-locates equal keys and is accepted, matching what + // EnforceDistribution accepts process-locally (e.g. an aggregate + // grouping on a superset of its input's join keys). + // DataFusion 54 does not export the type `satisfaction` returns, so a + // reference NotSatisfied value (an unknown partitioning can never + // satisfy a hash requirement) stands in for naming the variant. + let eq_properties = child.equivalence_properties(); + let not_satisfied = Partitioning::UnknownPartitioning(2).satisfaction( + requirement, + eq_properties, + true, + ); + let satisfaction = + child + .output_partitioning() + .satisfaction(requirement, eq_properties, true); + if satisfaction == not_satisfied { + return plan_err!( + "{} requires its input {idx} ({}) to be hash-partitioned on \ + specific keys, but that input's claimed partitioning ({}) does \ + not satisfy the requirement", + node.name(), + child.name(), + child.output_partitioning() + ); + } + // Provenance check: the claim must be globally true. A stage-local + // RepartitionExec mints the same claim, but it runs once per task over + // only that task's slice, so equal keys living in different tasks would + // never meet. + if !claims_are_global { + return plan_err!( + "{} requires its input {idx} ({}) to be hash-partitioned, but \ + in a {tasks}-task stage that partitioning was established \ + task-locally: equal keys living in different tasks would never \ + meet. The input must come through a NetworkShuffleExec", + node.name(), + child.name() + ); + } + } + } + } + } + + // Partitioned consumers zip partition `i` of every hash-required input within a task, + // so all such inputs must agree on partition count — otherwise equal keys land at + // different partition indices and never meet. + let mut hash_partitioned_counts = children + .iter() + .zip(&child_flows) + .zip(&requirements) + .enumerate() + .filter(|(_, ((_, flow), requirement))| { + matches!(requirement, Distribution::HashPartitioned(_)) + && matches!(flow, DataFlow::Partitioned { .. }) + }) + .map(|(idx, ((child, _), _))| (idx, child.output_partitioning().partition_count())); + if let Some((first_idx, first_count)) = hash_partitioned_counts.next() { + for (idx, count) in hash_partitioned_counts { + if count != first_count { + return plan_err!( + "{} requires co-partitioned inputs, but input {first_idx} claims \ + {first_count} partitions while input {idx} claims {count}: equal keys \ + would land at different partition indices and never meet", + node.name() + ); + } + } + } + + let any_partitioned = child_flows + .iter() + .any(|flow| matches!(flow, DataFlow::Partitioned { .. })); + if !any_partitioned { + // A deterministic operator over exclusively replicated inputs produces replicated + // output; legality is deferred to the consumer. + return Ok(DataFlow::Replicated); + } + + // Obligation (B): this node mixes replicated inputs into partitioned flow, so its output + // rows must be driven exclusively by the partitioned inputs. + for (idx, flow) in child_flows.iter().enumerate() { + if matches!(flow, DataFlow::Replicated) && emits_rows_driven_by(node, idx) { + return plan_err!( + "{} emits rows driven by its replicated input {idx}; each of the stage's \ + {tasks} task instances would emit those rows, duplicating them in the \ + stage output", + node.name() + ); + } + } + + // Provenance propagation. DataFusion's PlanProperties already carry each node's claimed + // partitioning through the operators — remapped through equivalence classes on renames, + // degraded when keys are projected away — so the *content* of the claim needs no + // tracking here; consumers check it with [Partitioning::satisfy] above. The one thing + // PlanProperties cannot express is whether a claim is globally true. A stage-local + // RepartitionExec is the only stage-local operator that mints new claims, and it runs + // once per task over only that task's slice, so its claims hold task-locally only. + // Every other operator inherits its claim from its children, preserving provenance. + let claims_are_global = !node.is::() + && child_flows.iter().all(|flow| match flow { + DataFlow::Partitioned { claims_are_global } => *claims_are_global, + DataFlow::Replicated => true, + }); + Ok(DataFlow::Partitioned { claims_are_global }) +} + +/// The one fact about an operator that no DataFusion API exposes: does it emit output rows +/// *driven by* the data of its `child_idx` input (as opposed to merely probing it)? An input +/// may be replicated across task instances only when the answer is no. +/// +/// Unknown operators default to `true`: a `UnionExec`, a limit, a window — anything that +/// forwards or produces rows from a replicated input — would duplicate them, so the +/// conservative answer is the correct default. New operators must opt in here explicitly. +fn emits_rows_driven_by(node: &Arc, child_idx: usize) -> bool { + if let Some(join) = node.downcast_ref::() { + return child_idx == 0 && !is_left_broadcast_safe(join.join_type()); + } + if let Some(join) = node.downcast_ref::() { + return child_idx == 0 && !is_left_broadcast_safe(join.join_type()); + } + if node.is::() { + // Every output row pairs a build row with a probe row, so output is probe-driven: + // with a partitioned probe side, each pair is produced exactly once. + return false; + } + true +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_utils::plans::TestPlanBuilder; + + /// Plans `query` through the full distributed planner. Since [validate_distributed_stages] + /// is wired into `create_physical_plan`, an invalid stage surfaces here as a planning + /// error rather than as a returned plan. Also returns the session config so tests can + /// re-run validation directly. + async fn try_plan_distributed( + query: &str, + broadcast_joins: bool, + ) -> (Result>, SessionConfig) { + let test_plan = TestPlanBuilder::new() + .target_partitions(3) + .num_workers(4) + .distributed_planner(true) + .broadcast_joins(broadcast_joins) + .build() + .await; + let ctx = test_plan.get_ctx(); + let session_cfg = ctx.copied_config(); + let plan = match ctx.sql(query).await { + Ok(df) => df.create_physical_plan().await, + Err(err) => Err(err), + }; + (plan, session_cfg) + } + + #[tokio::test] + async fn planner_rewrites_collect_left_join_to_partitioned() { + // LEFT is not broadcast-safe, so `insert_broadcast_execs` never broadcasts its build + // side — instead `normalize_collect_joins` rewrites the join to + // PartitionMode::Partitioned, which distributes correctly through shuffles. + let (plan, session_cfg) = try_plan_distributed( + r#"SELECT a."MinTemp", b."MaxTemp" + FROM weather a LEFT JOIN weather b ON a."RainToday" = b."RainToday""#, + true, + ) + .await; + let plan = plan.expect("expected planning to succeed"); + validate_distributed_stages(&plan, &session_cfg).expect("expected validation to pass"); + } + + #[tokio::test] + async fn planner_swaps_unbroadcast_nested_loop_left_join() { + // A Left NLJ is not broadcast-safe either; `normalize_collect_joins` swaps its + // inputs (Left becomes Right) so the emitting side becomes the partitioned probe + // side and the build side can be broadcast as usual. + let (plan, session_cfg) = try_plan_distributed( + r#"SELECT a."MinTemp", b."MaxTemp" + FROM weather a LEFT JOIN weather b ON a."MinTemp" < b."MaxTemp""#, + true, + ) + .await; + let plan = plan.expect("expected planning to succeed"); + validate_distributed_stages(&plan, &session_cfg).expect("expected validation to pass"); + } + + #[test] + fn rejects_collect_left_join_with_sliced_build_side() { + // The planner's task-count gate prevents this shape from ever being produced, so + // build it by hand to keep direct validator coverage: a CollectLeft join whose + // collected build side is a task-varying leaf behind a plain CoalescePartitionsExec. + // Each task would collect only its own slice of the build data. + let leaf = || -> Arc { Arc::new(EmptyExec::new(test_schema())) }; + let build: Arc = Arc::new(CoalescePartitionsExec::new(leaf())); + let on = vec![(column("a", &build.schema()), column("a", &test_schema()))]; + let join: Arc = Arc::new( + HashJoinExec::try_new( + build, + leaf(), + on, + None, + &JoinType::Inner, + None, + PartitionMode::CollectLeft, + NullEquality::NullEqualsNothing, + false, + ) + .unwrap(), + ); + let err = validate(&join).expect_err("expected validation to fail"); + assert!( + err.to_string().contains("requires a single partition"), + "unexpected error: {err}" + ); + } + + #[tokio::test] + async fn planner_caps_cross_join_with_broadcast_disabled() { + // Cross joins are always broadcast-safe, but with broadcast joins disabled there is + // no broadcast at all; the task-count gate caps the join's stage to a single task, + // producing a plan that validates cleanly. + let (plan, session_cfg) = try_plan_distributed( + r#"SELECT sum(a."MinTemp" + b."MaxTemp") + FROM weather a CROSS JOIN weather b"#, + false, + ) + .await; + let plan = plan.expect("expected planning to succeed"); + validate_distributed_stages(&plan, &session_cfg).expect("expected validation to pass"); + } + + #[tokio::test] + async fn accepts_broadcast_inner_join() { + // Inner is broadcast-safe: the build side arrives through a NetworkBroadcastExec + // (replicated), the probe side is a sliced leaf (partitioned), and an inner join + // only emits probe-driven rows. + let (plan, session_cfg) = try_plan_distributed( + r#"SELECT a."MinTemp", b."MaxTemp" + FROM weather a INNER JOIN weather b ON a."RainToday" = b."RainToday""#, + true, + ) + .await; + let plan = plan.expect("expected planning to succeed"); + validate_distributed_stages(&plan, &session_cfg).expect("expected validation to pass"); + } + + #[tokio::test] + async fn accepts_plan_with_broadcast_disabled() { + // With broadcast joins disabled the planner caps CollectLeft joins to a single task, + // so whatever stages remain must validate cleanly. + let (plan, session_cfg) = try_plan_distributed( + r#"SELECT a."MinTemp", b."MaxTemp" + FROM weather a LEFT JOIN weather b ON a."RainToday" = b."RainToday""#, + false, + ) + .await; + let plan = plan.expect("expected planning to succeed"); + validate_distributed_stages(&plan, &session_cfg).expect("expected validation to pass"); + } + + // ---- Hand-built plans below: shapes the real planner never produces, exercising the + // ---- checks directly. The fallback `&SessionConfig::default()` makes leaves replicated, + // ---- so we need to manually bypass it for tests that require task-varying leaves. + // ---- Wait, if they require task-varying leaves, we'll see if tests pass as-is. + + use crate::stage::LocalStage; + use datafusion::arrow::datatypes::{DataType, Field, Schema, SchemaRef}; + use datafusion::common::{JoinType, NullEquality}; + use datafusion::physical_expr::expressions::Column; + use datafusion::physical_expr::{EquivalenceProperties, PhysicalExpr}; + use datafusion::physical_plan::PlanProperties; + use datafusion::physical_plan::coalesce_partitions::CoalescePartitionsExec; + use datafusion::physical_plan::empty::EmptyExec; + use datafusion::physical_plan::execution_plan::{Boundedness, EmissionType}; + use datafusion::physical_plan::joins::PartitionMode; + use datafusion::physical_plan::projection::ProjectionExec; + use uuid::Uuid; + + fn test_schema() -> SchemaRef { + Arc::new(Schema::new(vec![ + Field::new("a", DataType::Int64, true), + Field::new("b", DataType::Int64, true), + ])) + } + + fn column(name: &str, schema: &Schema) -> Arc { + Arc::new(Column::new_with_schema(name, schema).unwrap()) + } + + /// A stand-in for a real shuffle: a [NetworkShuffleExec] whose stage claims + /// `Hash([key], partitions)`. Classified as globally partitioned by construction. + fn fake_shuffle(key: &str, partitions: usize) -> Arc { + let schema = test_schema(); + let properties = Arc::new(PlanProperties::new( + EquivalenceProperties::new(schema.clone()), + Partitioning::Hash(vec![column(key, &schema)], partitions), + EmissionType::Incremental, + Boundedness::Bounded, + )); + Arc::new(NetworkShuffleExec::from_stage( + Stage::Local(LocalStage { + query_id: Uuid::default(), + num: 1, + plan: Arc::new(EmptyExec::new(schema)), + tasks: 4, + metrics_set: Default::default(), + }), + properties, + )) + } + + /// A Partitioned hash join between `left` and `right` on `key` = `key`. + fn partitioned_join( + left: Arc, + right: Arc, + key: &str, + ) -> Arc { + let on = vec![(column(key, &left.schema()), column(key, &right.schema()))]; + Arc::new( + HashJoinExec::try_new( + left, + right, + on, + None, + &JoinType::Inner, + None, + PartitionMode::Partitioned, + NullEquality::NullEqualsNothing, + false, + ) + .unwrap(), + ) + } + + fn validate(plan: &Arc) -> Result<()> { + let cfg = SessionConfig::new(); + // Register a fallback desired task count handler that returns Desired(4) for all leaves. + // This simulates the old stub `TaskEstimator` for these tests. + let mut cfg = cfg; + crate::events::DesiredTaskCountHandlers::push_builtin( + &mut cfg, + Arc::new(|ev: crate::events::DesiredTaskCountEvent| { + if ev.plan.children().is_empty() { + Some(crate::events::DesiredTaskCountEventResponse::desired(4)) + } else { + None + } + }), + ); + validate_stage_plan(plan, 4, &cfg) + } + + #[test] + fn accepts_partitioned_join_over_matching_global_shuffles() { + let join = partitioned_join(fake_shuffle("a", 4), fake_shuffle("a", 4), "a"); + validate(&join).expect("expected validation to pass"); + } + + #[test] + fn rejects_partitioned_join_on_wrong_key() { + // Both sides are globally partitioned — but the left one on `b`, while the join + // requires partitioning on `a`. The provenance bit alone cannot see this; the + // claim-satisfaction check must. + let join = partitioned_join(fake_shuffle("b", 4), fake_shuffle("a", 4), "a"); + let err = validate(&join).expect_err("expected validation to fail"); + assert!( + err.to_string().contains("does not satisfy"), + "unexpected error: {err}" + ); + } + + #[test] + fn rejects_partitioned_join_over_stage_local_repartition() { + // The repartition claims exactly the required Hash([a], 4) — the claim satisfies, + // but it was minted inside the stage over the task's own slice of the leaf. + let leaf: Arc = Arc::new(EmptyExec::new(test_schema())); + let hash = Partitioning::Hash(vec![column("a", &test_schema())], 4); + let repartition: Arc = + Arc::new(RepartitionExec::try_new(leaf, hash).unwrap()); + let join = partitioned_join(repartition, fake_shuffle("a", 4), "a"); + let err = validate(&join).expect_err("expected validation to fail"); + assert!( + err.to_string().contains("established task-locally"), + "unexpected error: {err}" + ); + } + + #[test] + fn rejects_partitioned_join_with_mismatched_partition_counts() { + let join = partitioned_join(fake_shuffle("a", 4), fake_shuffle("a", 8), "a"); + let err = validate(&join).expect_err("expected validation to fail"); + assert!( + err.to_string().contains("co-partitioned"), + "unexpected error: {err}" + ); + } + + #[test] + fn accepts_renamed_key_through_projection() { + // Each side renames `a` to `x` above a shuffle hashed on `a`; the join keys + // reference `x`. DataFusion remaps the claimed Hash([a]) through the projection's + // equivalence mapping, so the satisfaction check passes under the new name. + let renamed = || -> Arc { + let shuffle = fake_shuffle("a", 4); + let exprs = vec![(column("a", &shuffle.schema()), "x".to_string())]; + Arc::new(ProjectionExec::try_new(exprs, shuffle).unwrap()) + }; + let join = partitioned_join(renamed(), renamed(), "x"); + validate(&join).expect("expected validation to pass"); + } +} diff --git a/tests/multi_task_collect_join_repros.rs b/tests/multi_task_collect_join_repros.rs new file mode 100644 index 00000000..e59c13ab --- /dev/null +++ b/tests/multi_task_collect_join_repros.rs @@ -0,0 +1,229 @@ +//! Reproducers for joins that collect their build (left) side producing wrong results when +//! placed in a multi-task stage without the build side being broadcast. +//! +//! A CollectLeft HashJoin, a NestedLoopJoin, and a CrossJoin all require the *complete* build +//! side in every task. `insert_broadcast_execs` only guarantees that for join types that don't +//! emit build-side rows (and only when broadcast joins are enabled), but the task-count logic +//! in `inject_network_boundaries` does not cap the remaining shapes to a single task. The +//! build-side scan then gets sliced across tasks like any other leaf, and each task joins its +//! slice of the build side against its slice of the probe side. +//! +//! The tables are laid out so the slicing is visible: `build_side` holds ids 0..100 split +//! sequentially across 4 files, while `probe_side` holds the same ids (each repeated 50 times) +//! rotated one file forward. A task therefore sees *different* ids from each table, and any +//! cross-task match is silently lost. +//! +//! These shapes are now handled by plan shaping (ported from the rj.use-datafusion-55 +//! branch): `normalize_collect_joins` rewrites build-side-emitting CollectLeft HashJoins to +//! PartitionMode::Partitioned and swaps build-side-emitting NestedLoopJoins so the emitting +//! side becomes the probe side, while the task-count gate in `inject_network_boundaries` +//! caps whatever has no distributed rewrite (Full joins, null-aware anti joins, and any of +//! these joins when broadcasts are disabled) to a single task. Stage validation +//! (`validate_distributed_stages`) remains the backstop that rejects anything unsafe at +//! planning time. Every test here asserts distributed results match single-node execution. + +#[cfg(all(feature = "integration", test))] +mod tests { + use arrow::array::{Int64Array, RecordBatch}; + use arrow::datatypes::{DataType, Field, Schema}; + use datafusion::error::Result; + use datafusion::physical_plan::{ExecutionPlan, collect}; + use datafusion::prelude::{ParquetReadOptions, SessionContext}; + use datafusion_distributed::test_utils::in_memory_channel_resolver::start_in_memory_context; + use datafusion_distributed::test_utils::property_based::compare_result_set; + use datafusion_distributed::{DefaultSessionBuilder, DistributedExt, display_plan_ascii}; + use parquet::arrow::ArrowWriter; + use std::fs; + use std::path::{Path, PathBuf}; + use std::sync::Arc; + use tokio::sync::OnceCell; + + const NUM_WORKERS: usize = 4; + const PARTITIONS: usize = 3; + const FILES_PER_TABLE: i64 = 4; + const IDS_PER_FILE: i64 = 25; + const PROBE_DUPLICATES: usize = 50; + + fn data_dir() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")).join("target/multi_task_collect_join_repros") + } + + static INIT: OnceCell<()> = OnceCell::const_new(); + + async fn ensure_data() { + INIT.get_or_init(|| async { + let dir = data_dir(); + let _ = fs::remove_dir_all(&dir); + // (table, rows per id, file rotation) + for (table, duplicates, rotation) in [ + ("build_side", 1usize, 0i64), + ("probe_side", PROBE_DUPLICATES, 1), + ] { + let table_dir = dir.join(table); + fs::create_dir_all(&table_dir).unwrap(); + for file_idx in 0..FILES_PER_TABLE { + let chunk = (file_idx + rotation) % FILES_PER_TABLE; + let ids = (chunk * IDS_PER_FILE..(chunk + 1) * IDS_PER_FILE) + .flat_map(|id| std::iter::repeat_n(id, duplicates)) + .collect::>(); + write_ids(&table_dir.join(format!("part-{file_idx}.parquet")), &ids); + } + } + }) + .await; + } + + fn write_ids(path: &Path, ids: &[i64]) { + let schema = Arc::new(Schema::new(vec![Field::new("id", DataType::Int64, true)])); + let batch = RecordBatch::try_new( + schema.clone(), + vec![Arc::new(Int64Array::from(ids.to_vec()))], + ) + .unwrap(); + let file = fs::File::create(path).unwrap(); + let mut writer = ArrowWriter::try_new(file, schema, None).unwrap(); + writer.write(&batch).unwrap(); + writer.close().unwrap(); + } + + async fn register_tables(ctx: &SessionContext) -> Result<()> { + for table in ["build_side", "probe_side"] { + ctx.register_parquet( + table, + data_dir().join(table).to_str().unwrap(), + ParquetReadOptions::default(), + ) + .await?; + } + Ok(()) + } + + async fn make_distributed_ctx(broadcast_joins: bool) -> Result { + let ctx = start_in_memory_context(NUM_WORKERS, DefaultSessionBuilder).await; + ctx.state_ref() + .write() + .config_mut() + .options_mut() + .execution + .target_partitions = PARTITIONS; + let ctx = ctx + .with_distributed_file_scan_config_bytes_per_partition(1)? + .with_distributed_broadcast_joins(broadcast_joins)?; + register_tables(&ctx).await?; + Ok(ctx) + } + + async fn run( + ctx: &SessionContext, + query: &str, + ) -> Result<(Arc, Vec)> { + let df = ctx.sql(query).await?; + let plan = df.create_physical_plan().await?; + let batches = collect(Arc::clone(&plan), ctx.task_ctx()).await?; + Ok((plan, batches)) + } + + /// Runs `query` on both contexts and asserts the distributed context produces the same + /// results as single-node execution. The task-count gate caps these join shapes to a + /// single task (and stage validation guarantees nothing unsafe slips through), so the + /// query must both plan and return correct results. + async fn assert_distributed_matches_single_node( + query: &str, + broadcast_joins: bool, + ) -> Result<()> { + ensure_data().await; + + let s_ctx = SessionContext::new(); + // Pin the baseline to the same partitioning as the distributed context: DataFusion + // 54's NestedLoopJoin emits spurious unmatched rows in Full/Left joins, and how many + // depends on the probe-side partition count (fixed upstream during the DataFusion 55 + // cycle, apache/datafusion#22791). With different target_partitions the two contexts + // disagree for reasons that have nothing to do with distribution. + s_ctx + .state_ref() + .write() + .config_mut() + .options_mut() + .execution + .target_partitions = PARTITIONS; + register_tables(&s_ctx).await?; + let d_ctx = make_distributed_ctx(broadcast_joins).await?; + + let (_, s_batches) = run(&s_ctx, query).await?; + let (d_plan, d_batches) = run(&d_ctx, query).await?; + println!( + "distributed plan:\n{}", + display_plan_ascii(d_plan.as_ref(), false) + ); + + let s_rows: usize = s_batches.iter().map(|b| b.num_rows()).sum(); + let d_rows: usize = d_batches.iter().map(|b| b.num_rows()).sum(); + println!("single-node rows: {s_rows}, distributed rows: {d_rows}"); + compare_result_set(&Ok(d_batches), &Ok(s_batches)) + } + + /// Case 1: CollectLeft HashJoin with a build-side-emitting join type (LeftSemi). + /// Broadcast joins are ON, but `insert_broadcast_execs` skips LeftSemi, and nothing caps + /// the stage to one task. Every id matches on a single node; distributed, a build id only + /// survives if its probe rows landed in the same task. + #[tokio::test] + async fn capped_collect_left_semi_hash_join_is_correct() -> Result<()> { + assert_distributed_matches_single_node( + "SELECT id FROM build_side WHERE id IN (SELECT id FROM probe_side)", + true, + ) + .await + } + + /// Case 2: anti join (`NOT IN`). Single-node: every build id exists in probe_side, + /// so zero rows. Distributed, each task only sees a slice of probe_side, so most build ids + /// look unmatched and phantom rows are emitted. + #[tokio::test] + async fn capped_not_in_anti_hash_join_is_correct() -> Result<()> { + assert_distributed_matches_single_node( + "SELECT id FROM build_side WHERE id NOT IN (SELECT id FROM probe_side)", + true, + ) + .await + } + + /// Case 3: NestedLoopJoin with a build-side-emitting join type (LeftSemi), produced + /// by a correlated EXISTS with a non-equi predicate (`p.id > b.id - 1 AND p.id < b.id + 1` + /// is `p.id = b.id` for integers, but expressed as inequalities so no hash join is possible). + #[tokio::test] + async fn capped_nested_loop_left_semi_join_is_correct() -> Result<()> { + assert_distributed_matches_single_node( + "SELECT b.id FROM build_side b WHERE EXISTS ( \ + SELECT 1 FROM probe_side p WHERE p.id > b.id - 1 AND p.id < b.id + 1)", + true, + ) + .await + } + + /// Case 4: Full NestedLoopJoin. Emits unmatched rows from BOTH sides, so no + /// broadcast orientation can ever be correct. Single-node: every row matches, no NULL + /// padding. Distributed: cross-task matches are lost and spurious NULL-padded rows appear. + #[tokio::test] + async fn capped_nested_loop_full_join_is_correct() -> Result<()> { + assert_distributed_matches_single_node( + "SELECT b.id, p.id FROM build_side b FULL JOIN probe_side p \ + ON p.id > b.id - 1 AND p.id < b.id + 1", + true, + ) + .await + } + + /// Case 5: CrossJoin with broadcast joins DISABLED, so no BroadcastExec exists at + /// all. Single-node: all 100 x 5000 = 500_000 pairs contribute to the sum. Distributed: + /// each task only pairs its slice of each side, so most pairs are never produced. + /// (A bare `count(*)` is folded to a constant from parquet statistics, so sum an + /// expression the optimizer cannot answer from metadata.) + #[tokio::test] + async fn capped_cross_join_broadcast_disabled_is_correct() -> Result<()> { + assert_distributed_matches_single_node( + "SELECT sum(b.id + p.id) AS pair_sum FROM build_side b CROSS JOIN probe_side p", + false, + ) + .await + } +} diff --git a/tests/tpcds_plans_test.rs b/tests/tpcds_plans_test.rs index 412c50a2..aef27129 100644 --- a/tests/tpcds_plans_test.rs +++ b/tests/tpcds_plans_test.rs @@ -881,46 +881,43 @@ mod tests { #[tokio::test] async fn test_tpcds_8() -> Result<()> { let display = test_tpcds_query("q8").await?; - assert_snapshot!(display, @r" + assert_snapshot!(display, @" ┌───── DistributedExec │ SortPreservingMergeExec: [s_store_name@0 ASC NULLS LAST], fetch=100 - │ [Stage 8] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 + │ [Stage 9] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 └────────────────────────────────────────────────── - ┌───── Stage 8 ── tasks=2, partitions=3 + ┌───── Stage 9 ── tasks=2, partitions=3 │ SortExec: TopK(fetch=100), expr=[s_store_name@0 ASC NULLS LAST], preserve_partitioning=[true] │ AggregateExec: mode=FinalPartitioned, gby=[s_store_name@0 as s_store_name], aggr=[sum(store_sales.ss_net_profit)] - │ [Stage 7] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 8] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 7 ── tasks=4, partitions=6 + ┌───── Stage 8 ── tasks=4, partitions=6 │ RepartitionExec: partitioning=Hash([s_store_name@0], 6), input_partitions=3 │ AggregateExec: mode=Partial, gby=[s_store_name@1 as s_store_name], aggr=[sum(store_sales.ss_net_profit)] │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(substr(v1.ca_zip,Int64(1),Int64(2))@1, substr(store.s_zip,Int64(1),Int64(2))@3)], projection=[ss_net_profit@2, s_store_name@3] │ CoalescePartitionsExec - │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=1 + │ [Stage 5] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=1 │ ProjectionExec: expr=[ss_net_profit@0 as ss_net_profit, s_store_name@1 as s_store_name, s_zip@2 as s_zip, substr(s_zip@2, 1, 2) as substr(store.s_zip,Int64(1),Int64(2))] │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(s_store_sk@0, ss_store_sk@0)], projection=[ss_net_profit@4, s_store_name@1, s_zip@2] │ CoalescePartitionsExec - │ [Stage 5] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 + │ [Stage 6] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ss_sold_date_sk@0)], projection=[ss_store_sk@2, ss_net_profit@3] │ CoalescePartitionsExec - │ [Stage 6] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ [Stage 7] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_sold_date_sk, ss_store_sk, ss_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_store_sk, ss_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_store_sk, ss_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_store_sk, ss_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=1, partitions=12 + ┌───── Stage 5 ── tasks=1, partitions=12 │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 │ ProjectionExec: expr=[ca_zip@0 as ca_zip, substr(ca_zip@0, 1, 2) as substr(v1.ca_zip,Int64(1),Int64(2))] - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(ca_zip@0, ca_zip@0)], NullsEqual: true - │ CoalescePartitionsExec + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(ca_zip@0, ca_zip@0)], NullsEqual: true + │ RepartitionExec: partitioning=Hash([ca_zip@0], 3), input_partitions=3 │ AggregateExec: mode=FinalPartitioned, gby=[ca_zip@0 as ca_zip], aggr=[] │ [Stage 1] => NetworkShuffleExec: output_partitions=3, input_tasks=4 - │ ProjectionExec: expr=[substr(ca_zip@0, 1, 5) as ca_zip] - │ FilterExec: count(Int64(1))@1 > 10, projection=[ca_zip@0] - │ AggregateExec: mode=FinalPartitioned, gby=[ca_zip@0 as ca_zip], aggr=[count(Int64(1))] - │ [Stage 3] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 4] => NetworkShuffleExec: output_partitions=3, input_tasks=2 └────────────────────────────────────────────────── ┌───── Stage 1 ── tasks=4, partitions=3 │ RepartitionExec: partitioning=Hash([ca_zip@0], 3), input_partitions=3 @@ -934,30 +931,37 @@ mod tests { │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_zip], file_type=parquet, predicate=substr(ca_zip@9, 1, 5) IN (SET) ([24128, 76232, 65084, 87816, 83926, 77556, 20548, 26231, 43848, 15126, 91137, 61265, 98294, 25782, 17920, 18426, 98235, 40081, 84093, 28577, 55565, 17183, 54601, 67897, 22752, 86284, 18376, 38607, 45200, 21756, 29741, 96765, 23932, 89360, 29839, 25989, 28898, 91068, 72550, 10390, 18845, 47770, 82636, 41367, 76638, 86198, 81312, 37126, 39192, 88424, 72175, 81426, 53672, 10445, 42666, 66864, 66708, 41248, 48583, 82276, 18842, 78890, 49448, 14089, 38122, 34425, 79077, 19849, 43285, 39861, 66162, 77610, 13695, 99543, 83444, 83041, 12305, 57665, 68341, 25003, 57834, 62878, 49130, 81096, 18840, 27700, 23470, 50412, 21195, 16021, 76107, 71954, 68309, 18119, 98359, 64544, 10336, 86379, 27068, 39736, 98569, 28915, 24206, 56529, 57647, 54917, 42961, 91110, 63981, 14922, 36420, 23006, 67467, 32754, 30903, 20260, 31671, 51798, 72325, 85816, 68621, 13955, 36446, 41766, 68806, 16725, 15146, 22744, 35850, 88086, 51649, 18270, 52867, 39972, 96976, 63792, 11376, 94898, 13595, 10516, 90225, 58943, 39371, 94945, 28587, 96576, 57855, 28488, 26105, 83933, 25858, 34322, 44438, 73171, 30122, 34102, 22685, 71256, 78451, 54364, 13354, 45375, 40558, 56458, 28286, 45266, 47305, 69399, 83921, 26233, 11101, 15371, 69913, 35942, 15882, 25631, 24610, 44165, 99076, 33786, 70738, 26653, 14328, 72305, 62496, 22152, 10144, 64147, 48425, 14663, 21076, 18799, 30450, 63089, 81019, 68893, 24996, 51200, 51211, 45692, 92712, 70466, 79994, 22437, 25280, 38935, 71791, 73134, 56571, 14060, 19505, 72425, 56575, 74351, 68786, 51650, 20004, 18383, 76614, 11634, 18906, 15765, 41368, 73241, 76698, 78567, 97189, 28545, 76231, 75691, 22246, 51061, 90578, 56691, 68014, 51103, 94167, 57047, 14867, 73520, 15734, 63435, 25733, 35474, 24676, 94627, 53535, 17879, 15559, 53268, 59166, 11928, 59402, 33282, 45721, 43933, 68101, 33515, 36634, 71286, 19736, 58058, 55253, 67473, 41918, 19515, 36495, 19430, 22351, 77191, 91393, 49156, 50298, 87501, 18652, 53179, 18767, 63193, 23968, 65164, 68880, 21286, 72823, 58470, 67301, 13394, 31016, 70372, 67030, 40604, 24317, 45748, 39127, 26065, 77721, 31029, 31880, 60576, 24671, 45549, 13376, 50016, 33123, 19769, 22927, 97789, 46081, 72151, 15723, 46136, 51949, 68100, 96888, 64528, 14171, 79777, 28709, 11489, 25103, 32213, 78668, 22245, 15798, 27156, 37930, 62971, 21337, 51622, 67853, 10567, 38415, 15455, 58263, 42029, 60279, 37125, 56240, 88190, 50308, 26859, 64457, 89091, 82136, 62377, 36233, 63837, 58078, 17043, 30010, 60099, 28810, 98025, 29178, 87343, 73273, 30469, 64034, 39516, 86057, 21309, 90257, 67875, 40162, 11356, 73650, 61810, 72013, 30431, 22461, 19512, 13375, 55307, 30625, 83849, 68908, 26689, 96451, 38193, 46820, 88885, 84935, 69035, 83144, 47537, 56616, 94983, 48033, 69952, 25486, 61547, 27385, 61860, 58048, 56910, 16807, 17871, 35258, 31387, 35458, 35576]) │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_zip], file_type=parquet, predicate=substr(ca_zip@9, 1, 5) IN (SET) ([24128, 76232, 65084, 87816, 83926, 77556, 20548, 26231, 43848, 15126, 91137, 61265, 98294, 25782, 17920, 18426, 98235, 40081, 84093, 28577, 55565, 17183, 54601, 67897, 22752, 86284, 18376, 38607, 45200, 21756, 29741, 96765, 23932, 89360, 29839, 25989, 28898, 91068, 72550, 10390, 18845, 47770, 82636, 41367, 76638, 86198, 81312, 37126, 39192, 88424, 72175, 81426, 53672, 10445, 42666, 66864, 66708, 41248, 48583, 82276, 18842, 78890, 49448, 14089, 38122, 34425, 79077, 19849, 43285, 39861, 66162, 77610, 13695, 99543, 83444, 83041, 12305, 57665, 68341, 25003, 57834, 62878, 49130, 81096, 18840, 27700, 23470, 50412, 21195, 16021, 76107, 71954, 68309, 18119, 98359, 64544, 10336, 86379, 27068, 39736, 98569, 28915, 24206, 56529, 57647, 54917, 42961, 91110, 63981, 14922, 36420, 23006, 67467, 32754, 30903, 20260, 31671, 51798, 72325, 85816, 68621, 13955, 36446, 41766, 68806, 16725, 15146, 22744, 35850, 88086, 51649, 18270, 52867, 39972, 96976, 63792, 11376, 94898, 13595, 10516, 90225, 58943, 39371, 94945, 28587, 96576, 57855, 28488, 26105, 83933, 25858, 34322, 44438, 73171, 30122, 34102, 22685, 71256, 78451, 54364, 13354, 45375, 40558, 56458, 28286, 45266, 47305, 69399, 83921, 26233, 11101, 15371, 69913, 35942, 15882, 25631, 24610, 44165, 99076, 33786, 70738, 26653, 14328, 72305, 62496, 22152, 10144, 64147, 48425, 14663, 21076, 18799, 30450, 63089, 81019, 68893, 24996, 51200, 51211, 45692, 92712, 70466, 79994, 22437, 25280, 38935, 71791, 73134, 56571, 14060, 19505, 72425, 56575, 74351, 68786, 51650, 20004, 18383, 76614, 11634, 18906, 15765, 41368, 73241, 76698, 78567, 97189, 28545, 76231, 75691, 22246, 51061, 90578, 56691, 68014, 51103, 94167, 57047, 14867, 73520, 15734, 63435, 25733, 35474, 24676, 94627, 53535, 17879, 15559, 53268, 59166, 11928, 59402, 33282, 45721, 43933, 68101, 33515, 36634, 71286, 19736, 58058, 55253, 67473, 41918, 19515, 36495, 19430, 22351, 77191, 91393, 49156, 50298, 87501, 18652, 53179, 18767, 63193, 23968, 65164, 68880, 21286, 72823, 58470, 67301, 13394, 31016, 70372, 67030, 40604, 24317, 45748, 39127, 26065, 77721, 31029, 31880, 60576, 24671, 45549, 13376, 50016, 33123, 19769, 22927, 97789, 46081, 72151, 15723, 46136, 51949, 68100, 96888, 64528, 14171, 79777, 28709, 11489, 25103, 32213, 78668, 22245, 15798, 27156, 37930, 62971, 21337, 51622, 67853, 10567, 38415, 15455, 58263, 42029, 60279, 37125, 56240, 88190, 50308, 26859, 64457, 89091, 82136, 62377, 36233, 63837, 58078, 17043, 30010, 60099, 28810, 98025, 29178, 87343, 73273, 30469, 64034, 39516, 86057, 21309, 90257, 67875, 40162, 11356, 73650, 61810, 72013, 30431, 22461, 19512, 13375, 55307, 30625, 83849, 68908, 26689, 96451, 38193, 46820, 88885, 84935, 69035, 83144, 47537, 56616, 94983, 48033, 69952, 25486, 61547, 27385, 61860, 58048, 56910, 16807, 17871, 35258, 31387, 35458, 35576]) └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=3 + ┌───── Stage 4 ── tasks=2, partitions=3 │ RepartitionExec: partitioning=Hash([ca_zip@0], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[ca_zip@0 as ca_zip], aggr=[count(Int64(1))] - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(c_current_addr_sk@0, ca_address_sk@0)], projection=[ca_zip@2] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ ProjectionExec: expr=[substr(ca_zip@0, 1, 5) as ca_zip] + │ FilterExec: count(Int64(1))@1 > 10, projection=[ca_zip@0] + │ AggregateExec: mode=FinalPartitioned, gby=[ca_zip@0 as ca_zip], aggr=[count(Int64(1))] + │ [Stage 3] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: c_preferred_cust_flag@1 = Y, projection=[c_current_addr_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_current_addr_sk, c_preferred_cust_flag], file_type=parquet, predicate=c_preferred_cust_flag@10 = Y, pruning_predicate=c_preferred_cust_flag_null_count@2 != row_count@3 AND c_preferred_cust_flag_min@0 <= Y AND Y <= c_preferred_cust_flag_max@1, required_guarantees=[c_preferred_cust_flag in (Y)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_current_addr_sk, c_preferred_cust_flag], file_type=parquet, predicate=c_preferred_cust_flag@10 = Y, pruning_predicate=c_preferred_cust_flag_null_count@2 != row_count@3 AND c_preferred_cust_flag_min@0 <= Y AND Y <= c_preferred_cust_flag_max@1, required_guarantees=[c_preferred_cust_flag in (Y)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_current_addr_sk, c_preferred_cust_flag], file_type=parquet, predicate=c_preferred_cust_flag@10 = Y, pruning_predicate=c_preferred_cust_flag_null_count@2 != row_count@3 AND c_preferred_cust_flag_min@0 <= Y AND Y <= c_preferred_cust_flag_max@1, required_guarantees=[c_preferred_cust_flag in (Y)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_current_addr_sk, c_preferred_cust_flag], file_type=parquet, predicate=c_preferred_cust_flag@10 = Y, pruning_predicate=c_preferred_cust_flag_null_count@2 != row_count@3 AND c_preferred_cust_flag_min@0 <= Y AND Y <= c_preferred_cust_flag_max@1, required_guarantees=[c_preferred_cust_flag in (Y)] + ┌───── Stage 3 ── tasks=4, partitions=6 + │ RepartitionExec: partitioning=Hash([ca_zip@0], 6), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[ca_zip@0 as ca_zip], aggr=[count(Int64(1))] + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(c_current_addr_sk@0, ca_address_sk@0)], projection=[ca_zip@2] + │ CoalescePartitionsExec + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 5 ── tasks=4, partitions=32 + ┌───── Stage 2 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: c_preferred_cust_flag@1 = Y, projection=[c_current_addr_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_current_addr_sk, c_preferred_cust_flag], file_type=parquet, predicate=c_preferred_cust_flag@10 = Y, pruning_predicate=c_preferred_cust_flag_null_count@2 != row_count@3 AND c_preferred_cust_flag_min@0 <= Y AND Y <= c_preferred_cust_flag_max@1, required_guarantees=[c_preferred_cust_flag in (Y)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_current_addr_sk, c_preferred_cust_flag], file_type=parquet, predicate=c_preferred_cust_flag@10 = Y, pruning_predicate=c_preferred_cust_flag_null_count@2 != row_count@3 AND c_preferred_cust_flag_min@0 <= Y AND Y <= c_preferred_cust_flag_max@1, required_guarantees=[c_preferred_cust_flag in (Y)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_current_addr_sk, c_preferred_cust_flag], file_type=parquet, predicate=c_preferred_cust_flag@10 = Y, pruning_predicate=c_preferred_cust_flag_null_count@2 != row_count@3 AND c_preferred_cust_flag_min@0 <= Y AND Y <= c_preferred_cust_flag_max@1, required_guarantees=[c_preferred_cust_flag in (Y)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_current_addr_sk, c_preferred_cust_flag], file_type=parquet, predicate=c_preferred_cust_flag@10 = Y, pruning_predicate=c_preferred_cust_flag_null_count@2 != row_count@3 AND c_preferred_cust_flag_min@0 <= Y AND Y <= c_preferred_cust_flag_max@1, required_guarantees=[c_preferred_cust_flag in (Y)] + └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=4, partitions=32 │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/store/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store/part-1.parquet:..]]}, projection=[s_store_sk, s_store_name, s_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] @@ -965,7 +969,7 @@ mod tests { │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/store/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store/part-3.parquet:..]]}, projection=[s_store_sk, s_store_name, s_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/store/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store/part-3.parquet:..]]}, projection=[s_store_sk, s_store_name, s_zip], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 6 ── tasks=4, partitions=48 + ┌───── Stage 7 ── tasks=4, partitions=48 │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 │ FilterExec: d_qoy@2 = 2 AND d_year@1 = 1998, projection=[d_date_sk@0] │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 @@ -981,323 +985,442 @@ mod tests { #[tokio::test] async fn test_tpcds_9() -> Result<()> { let display = test_tpcds_query("q9").await?; - assert_snapshot!(display, @r" + assert_snapshot!(display, @" ┌───── DistributedExec │ CoalescePartitionsExec - │ ProjectionExec: expr=[CASE WHEN count(*)@0 > 74129 THEN avg(store_sales.ss_ext_discount_amt)@1 ELSE avg(store_sales.ss_net_paid)@2 END as bucket1, CASE WHEN count(*)@3 > 122840 THEN avg(store_sales.ss_ext_discount_amt)@4 ELSE avg(store_sales.ss_net_paid)@5 END as bucket2, CASE WHEN count(*)@6 > 56580 THEN avg(store_sales.ss_ext_discount_amt)@7 ELSE avg(store_sales.ss_net_paid)@8 END as bucket3, CASE WHEN count(*)@9 > 10097 THEN avg(store_sales.ss_ext_discount_amt)@10 ELSE avg(store_sales.ss_net_paid)@11 END as bucket4, CASE WHEN count(*)@12 > 165306 THEN avg(store_sales.ss_ext_discount_amt)@13 ELSE avg(store_sales.ss_net_paid)@14 END as bucket5] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=1 - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ NestedLoopJoinExec: join_type=Left - │ CoalescePartitionsExec - │ [Stage 1] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] - │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ CoalescePartitionsExec - │ [Stage 4] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] - │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] - │ CoalescePartitionsExec - │ [Stage 5] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ CoalescePartitionsExec - │ [Stage 6] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ CoalescePartitionsExec - │ [Stage 7] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] - │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] - │ CoalescePartitionsExec - │ [Stage 8] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ CoalescePartitionsExec - │ [Stage 9] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ CoalescePartitionsExec - │ [Stage 10] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] - │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] - │ CoalescePartitionsExec - │ [Stage 11] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ CoalescePartitionsExec - │ [Stage 12] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ CoalescePartitionsExec - │ [Stage 13] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] - │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] - │ CoalescePartitionsExec - │ [Stage 14] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ CoalescePartitionsExec - │ [Stage 15] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ CoalescePartitionsExec - │ [Stage 16] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + │ [Stage 31] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=12 - │ FilterExec: r_reason_sk@0 = 1, projection=[] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..]]}, projection=[r_reason_sk], file_type=parquet, predicate=r_reason_sk@0 = 1, pruning_predicate=r_reason_sk_null_count@2 != row_count@3 AND r_reason_sk_min@0 <= 1 AND 1 <= r_reason_sk_max@1, required_guarantees=[r_reason_sk in (1)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..]]}, projection=[r_reason_sk], file_type=parquet, predicate=r_reason_sk@0 = 1, pruning_predicate=r_reason_sk_null_count@2 != row_count@3 AND r_reason_sk_min@0 <= 1 AND 1 <= r_reason_sk_max@1, required_guarantees=[r_reason_sk in (1)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/reason/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/reason/part-2.parquet:..]]}, projection=[r_reason_sk], file_type=parquet, predicate=r_reason_sk@0 = 1, pruning_predicate=r_reason_sk_null_count@2 != row_count@3 AND r_reason_sk_min@0 <= 1 AND 1 <= r_reason_sk_max@1, required_guarantees=[r_reason_sk in (1)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/reason/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/reason/part-3.parquet:..]]}, projection=[r_reason_sk], file_type=parquet, predicate=r_reason_sk@0 = 1, pruning_predicate=r_reason_sk_null_count@2 != row_count@3 AND r_reason_sk_min@0 <= 1 AND 1 <= r_reason_sk_max@1, required_guarantees=[r_reason_sk in (1)] - └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] - │ FilterExec: ss_quantity@0 >= 1 AND ss_quantity@0 <= 20, projection=[] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ FilterExec: ss_quantity@0 >= 1 AND ss_quantity@0 <= 20, projection=[ss_ext_discount_amt@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ FilterExec: ss_quantity@0 >= 1 AND ss_quantity@0 <= 20, projection=[ss_net_paid@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 5 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] - │ FilterExec: ss_quantity@0 >= 21 AND ss_quantity@0 <= 40, projection=[] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 6 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ FilterExec: ss_quantity@0 >= 21 AND ss_quantity@0 <= 40, projection=[ss_ext_discount_amt@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 7 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ FilterExec: ss_quantity@0 >= 21 AND ss_quantity@0 <= 40, projection=[ss_net_paid@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 8 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] - │ FilterExec: ss_quantity@0 >= 41 AND ss_quantity@0 <= 60, projection=[] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 9 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ FilterExec: ss_quantity@0 >= 41 AND ss_quantity@0 <= 60, projection=[ss_ext_discount_amt@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 10 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ FilterExec: ss_quantity@0 >= 41 AND ss_quantity@0 <= 60, projection=[ss_net_paid@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 11 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] - │ FilterExec: ss_quantity@0 >= 61 AND ss_quantity@0 <= 80, projection=[] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 12 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ FilterExec: ss_quantity@0 >= 61 AND ss_quantity@0 <= 80, projection=[ss_ext_discount_amt@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 13 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ FilterExec: ss_quantity@0 >= 61 AND ss_quantity@0 <= 80, projection=[ss_net_paid@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 14 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] - │ FilterExec: ss_quantity@0 >= 81 AND ss_quantity@0 <= 100, projection=[] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 15 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] - │ FilterExec: ss_quantity@0 >= 81 AND ss_quantity@0 <= 100, projection=[ss_ext_discount_amt@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 16 ── tasks=4, partitions=12 - │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] - │ FilterExec: ss_quantity@0 >= 81 AND ss_quantity@0 <= 100, projection=[ss_net_paid@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] - └────────────────────────────────────────────────── + ┌───── Stage 31 ── tasks=4, partitions=12 + │ ProjectionExec: expr=[CASE WHEN count(*)@0 > 74129 THEN avg(store_sales.ss_ext_discount_amt)@1 ELSE avg(store_sales.ss_net_paid)@2 END as bucket1, CASE WHEN count(*)@3 > 122840 THEN avg(store_sales.ss_ext_discount_amt)@4 ELSE avg(store_sales.ss_net_paid)@5 END as bucket2, CASE WHEN count(*)@6 > 56580 THEN avg(store_sales.ss_ext_discount_amt)@7 ELSE avg(store_sales.ss_net_paid)@8 END as bucket3, CASE WHEN count(*)@9 > 10097 THEN avg(store_sales.ss_ext_discount_amt)@10 ELSE avg(store_sales.ss_net_paid)@11 END as bucket4, CASE WHEN count(*)@12 > 165306 THEN avg(store_sales.ss_ext_discount_amt)@13 ELSE avg(store_sales.ss_net_paid)@14 END as bucket5] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=3 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@6 as avg(store_sales.ss_net_paid), count(*)@7 as count(*), avg(store_sales.ss_ext_discount_amt)@8 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@9 as avg(store_sales.ss_net_paid), count(*)@10 as count(*), avg(store_sales.ss_ext_discount_amt)@11 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@12 as avg(store_sales.ss_net_paid), count(*)@13 as count(*), avg(store_sales.ss_ext_discount_amt)@14 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@0 as avg(store_sales.ss_net_paid)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@6 as avg(store_sales.ss_net_paid), count(*)@7 as count(*), avg(store_sales.ss_ext_discount_amt)@8 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@9 as avg(store_sales.ss_net_paid), count(*)@10 as count(*), avg(store_sales.ss_ext_discount_amt)@11 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@12 as avg(store_sales.ss_net_paid), count(*)@13 as count(*), avg(store_sales.ss_ext_discount_amt)@0 as avg(store_sales.ss_ext_discount_amt)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@6 as avg(store_sales.ss_net_paid), count(*)@7 as count(*), avg(store_sales.ss_ext_discount_amt)@8 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@9 as avg(store_sales.ss_net_paid), count(*)@10 as count(*), avg(store_sales.ss_ext_discount_amt)@11 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@12 as avg(store_sales.ss_net_paid), count(*)@0 as count(*)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 6] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@6 as avg(store_sales.ss_net_paid), count(*)@7 as count(*), avg(store_sales.ss_ext_discount_amt)@8 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@9 as avg(store_sales.ss_net_paid), count(*)@10 as count(*), avg(store_sales.ss_ext_discount_amt)@11 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@0 as avg(store_sales.ss_net_paid)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 8] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@6 as avg(store_sales.ss_net_paid), count(*)@7 as count(*), avg(store_sales.ss_ext_discount_amt)@8 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@9 as avg(store_sales.ss_net_paid), count(*)@10 as count(*), avg(store_sales.ss_ext_discount_amt)@0 as avg(store_sales.ss_ext_discount_amt)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 10] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@6 as avg(store_sales.ss_net_paid), count(*)@7 as count(*), avg(store_sales.ss_ext_discount_amt)@8 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@9 as avg(store_sales.ss_net_paid), count(*)@0 as count(*)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 12] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@6 as avg(store_sales.ss_net_paid), count(*)@7 as count(*), avg(store_sales.ss_ext_discount_amt)@8 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@0 as avg(store_sales.ss_net_paid)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 14] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@6 as avg(store_sales.ss_net_paid), count(*)@7 as count(*), avg(store_sales.ss_ext_discount_amt)@0 as avg(store_sales.ss_ext_discount_amt)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 16] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@6 as avg(store_sales.ss_net_paid), count(*)@0 as count(*)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 18] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@5 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@0 as avg(store_sales.ss_net_paid)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 20] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@4 as count(*), avg(store_sales.ss_ext_discount_amt)@0 as avg(store_sales.ss_ext_discount_amt)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 22] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@3 as avg(store_sales.ss_net_paid), count(*)@0 as count(*)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 24] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@2 as avg(store_sales.ss_ext_discount_amt), avg(store_sales.ss_net_paid)@0 as avg(store_sales.ss_net_paid)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 26] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@1 as count(*), avg(store_sales.ss_ext_discount_amt)@0 as avg(store_sales.ss_ext_discount_amt)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 28] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ ProjectionExec: expr=[count(*)@0 as count(*)] + │ NestedLoopJoinExec: join_type=Right + │ CoalescePartitionsExec + │ [Stage 30] => NetworkBroadcastExec: partitions_per_consumer=1, stage_partitions=4, input_tasks=1 + │ FilterExec: r_reason_sk@0 = 1, projection=[] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..]]}, projection=[r_reason_sk], file_type=parquet, predicate=r_reason_sk@0 = 1, pruning_predicate=r_reason_sk_null_count@2 != row_count@3 AND r_reason_sk_min@0 <= 1 AND 1 <= r_reason_sk_max@1, required_guarantees=[r_reason_sk in (1)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..]]}, projection=[r_reason_sk], file_type=parquet, predicate=r_reason_sk@0 = 1, pruning_predicate=r_reason_sk_null_count@2 != row_count@3 AND r_reason_sk_min@0 <= 1 AND 1 <= r_reason_sk_max@1, required_guarantees=[r_reason_sk in (1)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/reason/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/reason/part-2.parquet:..]]}, projection=[r_reason_sk], file_type=parquet, predicate=r_reason_sk@0 = 1, pruning_predicate=r_reason_sk_null_count@2 != row_count@3 AND r_reason_sk_min@0 <= 1 AND 1 <= r_reason_sk_max@1, required_guarantees=[r_reason_sk in (1)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/reason/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/reason/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/reason/part-3.parquet:..]]}, projection=[r_reason_sk], file_type=parquet, predicate=r_reason_sk@0 = 1, pruning_predicate=r_reason_sk_null_count@2 != row_count@3 AND r_reason_sk_min@0 <= 1 AND 1 <= r_reason_sk_max@1, required_guarantees=[r_reason_sk in (1)] + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ FilterExec: ss_quantity@0 >= 81 AND ss_quantity@0 <= 100, projection=[ss_net_paid@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ CoalescePartitionsExec + │ [Stage 3] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ FilterExec: ss_quantity@0 >= 81 AND ss_quantity@0 <= 100, projection=[ss_ext_discount_amt@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] + │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] + │ CoalescePartitionsExec + │ [Stage 5] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] + │ FilterExec: ss_quantity@0 >= 81 AND ss_quantity@0 <= 100, projection=[] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 81 AND ss_quantity@10 <= 100, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 81 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 100, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 8 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ CoalescePartitionsExec + │ [Stage 7] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 7 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ FilterExec: ss_quantity@0 >= 61 AND ss_quantity@0 <= 80, projection=[ss_net_paid@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 10 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ CoalescePartitionsExec + │ [Stage 9] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 9 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ FilterExec: ss_quantity@0 >= 61 AND ss_quantity@0 <= 80, projection=[ss_ext_discount_amt@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 12 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] + │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] + │ CoalescePartitionsExec + │ [Stage 11] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 11 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] + │ FilterExec: ss_quantity@0 >= 61 AND ss_quantity@0 <= 80, projection=[] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 61 AND ss_quantity@10 <= 80, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 61 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 80, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 14 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ CoalescePartitionsExec + │ [Stage 13] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 13 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ FilterExec: ss_quantity@0 >= 41 AND ss_quantity@0 <= 60, projection=[ss_net_paid@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 16 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ CoalescePartitionsExec + │ [Stage 15] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 15 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ FilterExec: ss_quantity@0 >= 41 AND ss_quantity@0 <= 60, projection=[ss_ext_discount_amt@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 18 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] + │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] + │ CoalescePartitionsExec + │ [Stage 17] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 17 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] + │ FilterExec: ss_quantity@0 >= 41 AND ss_quantity@0 <= 60, projection=[] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 41 AND ss_quantity@10 <= 60, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 41 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 60, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 20 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ CoalescePartitionsExec + │ [Stage 19] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 19 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ FilterExec: ss_quantity@0 >= 21 AND ss_quantity@0 <= 40, projection=[ss_net_paid@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 22 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ CoalescePartitionsExec + │ [Stage 21] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 21 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ FilterExec: ss_quantity@0 >= 21 AND ss_quantity@0 <= 40, projection=[ss_ext_discount_amt@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 24 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] + │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] + │ CoalescePartitionsExec + │ [Stage 23] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 23 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] + │ FilterExec: ss_quantity@0 >= 21 AND ss_quantity@0 <= 40, projection=[] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 21 AND ss_quantity@10 <= 40, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 21 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 40, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 26 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ CoalescePartitionsExec + │ [Stage 25] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 25 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_net_paid)] + │ FilterExec: ss_quantity@0 >= 1 AND ss_quantity@0 <= 20, projection=[ss_net_paid@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_net_paid], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 28 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ AggregateExec: mode=Final, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ CoalescePartitionsExec + │ [Stage 27] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 27 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[avg(store_sales.ss_ext_discount_amt)] + │ FilterExec: ss_quantity@0 >= 1 AND ss_quantity@0 <= 20, projection=[ss_ext_discount_amt@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity, ss_ext_discount_amt], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 30 ── tasks=1, partitions=4 + │ BroadcastExec: input_partitions=1, consumer_tasks=4, output_partitions=4 + │ ProjectionExec: expr=[count(Int64(1))@0 as count(*)] + │ AggregateExec: mode=Final, gby=[], aggr=[count(Int64(1))] + │ CoalescePartitionsExec + │ [Stage 29] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 29 ── tasks=4, partitions=12 + │ AggregateExec: mode=Partial, gby=[], aggr=[count(Int64(1))] + │ FilterExec: ss_quantity@0 >= 1 AND ss_quantity@0 <= 20, projection=[] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_quantity], file_type=parquet, predicate=ss_quantity@10 >= 1 AND ss_quantity@10 <= 20, pruning_predicate=ss_quantity_null_count@1 != row_count@2 AND ss_quantity_max@0 >= 1 AND ss_quantity_null_count@1 != row_count@2 AND ss_quantity_min@3 <= 20, required_guarantees=[] + └────────────────────────────────────────────────── "); Ok(()) } #[tokio::test] async fn test_tpcds_10() -> Result<()> { let display = test_tpcds_query("q10").await?; - assert_snapshot!(display, @r" + assert_snapshot!(display, @" ┌───── DistributedExec │ SortPreservingMergeExec: [cd_gender@0 ASC NULLS LAST, cd_marital_status@1 ASC NULLS LAST, cd_education_status@2 ASC NULLS LAST, cd_purchase_estimate@4 ASC NULLS LAST, cd_credit_rating@6 ASC NULLS LAST, cd_dep_count@8 ASC NULLS LAST, cd_dep_employed_count@10 ASC NULLS LAST, cd_dep_college_count@12 ASC NULLS LAST], fetch=100 │ SortExec: TopK(fetch=100), expr=[cd_gender@0 ASC NULLS LAST, cd_marital_status@1 ASC NULLS LAST, cd_education_status@2 ASC NULLS LAST, cd_purchase_estimate@4 ASC NULLS LAST, cd_credit_rating@6 ASC NULLS LAST, cd_dep_count@8 ASC NULLS LAST, cd_dep_employed_count@10 ASC NULLS LAST, cd_dep_college_count@12 ASC NULLS LAST], preserve_partitioning=[true] │ ProjectionExec: expr=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, count(Int64(1))@8 as cnt1, cd_purchase_estimate@3 as cd_purchase_estimate, count(Int64(1))@8 as cnt2, cd_credit_rating@4 as cd_credit_rating, count(Int64(1))@8 as cnt3, cd_dep_count@5 as cd_dep_count, count(Int64(1))@8 as cnt4, cd_dep_employed_count@6 as cd_dep_employed_count, count(Int64(1))@8 as cnt5, cd_dep_college_count@7 as cd_dep_college_count, count(Int64(1))@8 as cnt6] │ AggregateExec: mode=FinalPartitioned, gby=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, cd_purchase_estimate@3 as cd_purchase_estimate, cd_credit_rating@4 as cd_credit_rating, cd_dep_count@5 as cd_dep_count, cd_dep_employed_count@6 as cd_dep_employed_count, cd_dep_college_count@7 as cd_dep_college_count], aggr=[count(Int64(1))] - │ RepartitionExec: partitioning=Hash([cd_gender@0, cd_marital_status@1, cd_education_status@2, cd_purchase_estimate@3, cd_credit_rating@4, cd_dep_count@5, cd_dep_employed_count@6, cd_dep_college_count@7], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, cd_purchase_estimate@3 as cd_purchase_estimate, cd_credit_rating@4 as cd_credit_rating, cd_dep_count@5 as cd_dep_count, cd_dep_employed_count@6 as cd_dep_employed_count, cd_dep_college_count@7 as cd_dep_college_count], aggr=[count(Int64(1))] - │ FilterExec: mark@8 OR mark@9, projection=[cd_gender@0, cd_marital_status@1, cd_education_status@2, cd_purchase_estimate@3, cd_credit_rating@4, cd_dep_count@5, cd_dep_employed_count@6, cd_dep_college_count@7] - │ HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(c_customer_sk@0, cs_ship_customer_sk@0)], projection=[cd_gender@1, cd_marital_status@2, cd_education_status@3, cd_purchase_estimate@4, cd_credit_rating@5, cd_dep_count@6, cd_dep_employed_count@7, cd_dep_college_count@8, mark@9, mark@10] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(c_customer_sk@0, ws_bill_customer_sk@0)] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(c_customer_sk@0, ss_customer_sk@0)] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ss_sold_date_sk@0)], projection=[ss_customer_sk@2] - │ CoalescePartitionsExec - │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_sold_date_sk@0)], projection=[ws_bill_customer_sk@2] - │ CoalescePartitionsExec - │ [Stage 5] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, cs_sold_date_sk@0)], projection=[cs_ship_customer_sk@2] - │ CoalescePartitionsExec - │ [Stage 6] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ [Stage 12] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(c_current_cdemo_sk@1, cd_demo_sk@0)], projection=[c_customer_sk@0, cd_gender@3, cd_marital_status@4, cd_education_status@5, cd_purchase_estimate@6, cd_credit_rating@7, cd_dep_count@8, cd_dep_employed_count@9, cd_dep_college_count@10] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + ┌───── Stage 12 ── tasks=4, partitions=3 + │ RepartitionExec: partitioning=Hash([cd_gender@0, cd_marital_status@1, cd_education_status@2, cd_purchase_estimate@3, cd_credit_rating@4, cd_dep_count@5, cd_dep_employed_count@6, cd_dep_college_count@7], 3), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, cd_purchase_estimate@3 as cd_purchase_estimate, cd_credit_rating@4 as cd_credit_rating, cd_dep_count@5 as cd_dep_count, cd_dep_employed_count@6 as cd_dep_employed_count, cd_dep_college_count@7 as cd_dep_college_count], aggr=[count(Int64(1))] + │ FilterExec: mark@8 OR mark@9, projection=[cd_gender@0, cd_marital_status@1, cd_education_status@2, cd_purchase_estimate@3, cd_credit_rating@4, cd_dep_count@5, cd_dep_employed_count@6, cd_dep_college_count@7] + │ HashJoinExec: mode=Partitioned, join_type=LeftMark, on=[(c_customer_sk@0, cs_ship_customer_sk@0)], projection=[cd_gender@1, cd_marital_status@2, cd_education_status@3, cd_purchase_estimate@4, cd_credit_rating@5, cd_dep_count@6, cd_dep_employed_count@7, cd_dep_college_count@8, mark@9, mark@10] + │ [Stage 9] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 11] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, c_current_addr_sk@2)], projection=[c_customer_sk@1, c_current_cdemo_sk@2] + ┌───── Stage 9 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftMark, on=[(c_customer_sk@0, ws_bill_customer_sk@0)] + │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 8] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(c_customer_sk@0, ss_customer_sk@0)] + │ [Stage 3] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(c_current_cdemo_sk@1, cd_demo_sk@0)], projection=[c_customer_sk@0, cd_gender@3, cd_marital_status@4, cd_education_status@5, cd_purchase_estimate@6, cd_credit_rating@7, cd_dep_count@8, cd_dep_employed_count@9, cd_dep_college_count@10] + │ CoalescePartitionsExec + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, c_current_addr_sk@2)], projection=[c_customer_sk@1, c_current_cdemo_sk@2] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: ca_county@1 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), projection=[ca_address_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_county], file_type=parquet, predicate=ca_county@7 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), pruning_predicate=ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Rush County AND Rush County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Toole County AND Toole County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Jefferson County AND Jefferson County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Dona Ana County AND Dona Ana County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= La Porte County AND La Porte County <= ca_county_max@1, required_guarantees=[ca_county in (Dona Ana County, Jefferson County, La Porte County, Rush County, Toole County)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_county], file_type=parquet, predicate=ca_county@7 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), pruning_predicate=ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Rush County AND Rush County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Toole County AND Toole County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Jefferson County AND Jefferson County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Dona Ana County AND Dona Ana County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= La Porte County AND La Porte County <= ca_county_max@1, required_guarantees=[ca_county in (Dona Ana County, Jefferson County, La Porte County, Rush County, Toole County)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_county], file_type=parquet, predicate=ca_county@7 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), pruning_predicate=ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Rush County AND Rush County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Toole County AND Toole County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Jefferson County AND Jefferson County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Dona Ana County AND Dona Ana County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= La Porte County AND La Porte County <= ca_county_max@1, required_guarantees=[ca_county in (Dona Ana County, Jefferson County, La Porte County, Rush County, Toole County)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_county], file_type=parquet, predicate=ca_county@7 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), pruning_predicate=ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Rush County AND Rush County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Toole County AND Toole County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Jefferson County AND Jefferson County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Dona Ana County AND Dona Ana County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= La Porte County AND La Porte County <= ca_county_max@1, required_guarantees=[ca_county in (Dona Ana County, Jefferson County, La Porte County, Rush County, Toole County)] + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ss_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ss_sold_date_sk@0)], projection=[ss_customer_sk@2] + │ CoalescePartitionsExec + │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_year@1 = 2002 AND d_moy@2 >= 1 AND d_moy@2 <= 4, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + └────────────────────────────────────────────────── + ┌───── Stage 8 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_bill_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_sold_date_sk@0)], projection=[ws_bill_customer_sk@2] + │ CoalescePartitionsExec + │ [Stage 7] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 7 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_year@1 = 2002 AND d_moy@2 >= 1 AND d_moy@2 <= 4, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + └────────────────────────────────────────────────── + ┌───── Stage 11 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([cs_ship_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, cs_sold_date_sk@0)], projection=[cs_ship_customer_sk@2] │ CoalescePartitionsExec - │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ [Stage 10] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=48 + ┌───── Stage 10 ── tasks=4, partitions=48 │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: ca_county@1 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), projection=[ca_address_sk@0] + │ FilterExec: d_year@1 = 2002 AND d_moy@2 >= 1 AND d_moy@2 <= 4, projection=[d_date_sk@0] │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_county], file_type=parquet, predicate=ca_county@7 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), pruning_predicate=ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Rush County AND Rush County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Toole County AND Toole County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Jefferson County AND Jefferson County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Dona Ana County AND Dona Ana County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= La Porte County AND La Porte County <= ca_county_max@1, required_guarantees=[ca_county in (Dona Ana County, Jefferson County, La Porte County, Rush County, Toole County)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_county], file_type=parquet, predicate=ca_county@7 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), pruning_predicate=ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Rush County AND Rush County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Toole County AND Toole County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Jefferson County AND Jefferson County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Dona Ana County AND Dona Ana County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= La Porte County AND La Porte County <= ca_county_max@1, required_guarantees=[ca_county in (Dona Ana County, Jefferson County, La Porte County, Rush County, Toole County)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_county], file_type=parquet, predicate=ca_county@7 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), pruning_predicate=ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Rush County AND Rush County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Toole County AND Toole County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Jefferson County AND Jefferson County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Dona Ana County AND Dona Ana County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= La Porte County AND La Porte County <= ca_county_max@1, required_guarantees=[ca_county in (Dona Ana County, Jefferson County, La Porte County, Rush County, Toole County)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_county], file_type=parquet, predicate=ca_county@7 IN (SET) ([Rush County, Toole County, Jefferson County, Dona Ana County, La Porte County]), pruning_predicate=ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Rush County AND Rush County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Toole County AND Toole County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Jefferson County AND Jefferson County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= Dona Ana County AND Dona Ana County <= ca_county_max@1 OR ca_county_null_count@2 != row_count@3 AND ca_county_min@0 <= La Porte County AND La Porte County <= ca_county_max@1, required_guarantees=[ca_county in (Dona Ana County, Jefferson County, La Porte County, Rush County, Toole County)] + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_year@1 = 2002 AND d_moy@2 >= 1 AND d_moy@2 <= 4, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - └────────────────────────────────────────────────── - ┌───── Stage 5 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_year@1 = 2002 AND d_moy@2 >= 1 AND d_moy@2 <= 4, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - └────────────────────────────────────────────────── - ┌───── Stage 6 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_year@1 = 2002 AND d_moy@2 >= 1 AND d_moy@2 <= 4, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2002 AND d_moy@8 >= 1 AND d_moy@8 <= 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 1 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 4, required_guarantees=[d_year in (2002)] - └────────────────────────────────────────────────── "); Ok(()) } @@ -2375,72 +2498,95 @@ mod tests { #[tokio::test] async fn test_tpcds_16() -> Result<()> { let display = test_tpcds_query("q16").await?; - assert_snapshot!(display, @r" + assert_snapshot!(display, @" ┌───── DistributedExec │ ProjectionExec: expr=[count(alias1)@0 as order count, sum(alias2)@1 as total shipping cost, sum(alias3)@2 as total net profit] │ GlobalLimitExec: skip=0, fetch=100 │ AggregateExec: mode=Final, gby=[], aggr=[count(alias1), sum(alias2), sum(alias3)] │ CoalescePartitionsExec - │ AggregateExec: mode=Partial, gby=[], aggr=[count(alias1), sum(alias2), sum(alias3)] - │ AggregateExec: mode=FinalPartitioned, gby=[alias1@0 as alias1], aggr=[sum(cs1.cs_ext_ship_cost) as alias2, sum(cs1.cs_net_profit) as alias3] - │ RepartitionExec: partitioning=Hash([alias1@0], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[cs_order_number@0 as alias1], aggr=[sum(cs1.cs_ext_ship_cost) as alias2, sum(cs1.cs_net_profit) as alias3] - │ HashJoinExec: mode=CollectLeft, join_type=LeftAnti, on=[(cs_order_number@0, cr_order_number@0)] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(cs_order_number@1, cs_order_number@1)], filter=cs_warehouse_sk@0 != cs_warehouse_sk@1, projection=[cs_order_number@1, cs_ext_ship_cost@2, cs_net_profit@3] - │ CoalescePartitionsExec - │ [Stage 4] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_warehouse_sk, cs_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-3.parquet:..]]}, projection=[cr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ [Stage 9] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(cc_call_center_sk@0, cs_call_center_sk@0)], projection=[cs_warehouse_sk@2, cs_order_number@3, cs_ext_ship_cost@4, cs_net_profit@5] - │ CoalescePartitionsExec - │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, cs_ship_addr_sk@0)], projection=[cs_call_center_sk@2, cs_warehouse_sk@3, cs_order_number@4, cs_ext_ship_cost@5, cs_net_profit@6] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, cs_ship_date_sk@0)], projection=[cs_ship_addr_sk@2, cs_call_center_sk@3, cs_warehouse_sk@4, cs_order_number@5, cs_ext_ship_cost@6, cs_net_profit@7] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..]]}, projection=[cs_ship_date_sk, cs_ship_addr_sk, cs_call_center_sk, cs_warehouse_sk, cs_order_number, cs_ext_ship_cost, cs_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_ship_date_sk, cs_ship_addr_sk, cs_call_center_sk, cs_warehouse_sk, cs_order_number, cs_ext_ship_cost, cs_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_ship_date_sk, cs_ship_addr_sk, cs_call_center_sk, cs_warehouse_sk, cs_order_number, cs_ext_ship_cost, cs_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_ship_date_sk, cs_ship_addr_sk, cs_call_center_sk, cs_warehouse_sk, cs_order_number, cs_ext_ship_cost, cs_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + ┌───── Stage 9 ── tasks=2, partitions=3 + │ AggregateExec: mode=Partial, gby=[], aggr=[count(alias1), sum(alias2), sum(alias3)] + │ AggregateExec: mode=FinalPartitioned, gby=[alias1@0 as alias1], aggr=[sum(cs1.cs_ext_ship_cost) as alias2, sum(cs1.cs_net_profit) as alias3] + │ [Stage 8] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: cc_county@1 = Williamson County, projection=[cc_call_center_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/call_center/part-1.parquet:..]]}, projection=[cc_call_center_sk, cc_county], file_type=parquet, predicate=cc_county@25 = Williamson County, pruning_predicate=cc_county_null_count@2 != row_count@3 AND cc_county_min@0 <= Williamson County AND Williamson County <= cc_county_max@1, required_guarantees=[cc_county in (Williamson County)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/call_center/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/call_center/part-2.parquet:..]]}, projection=[cc_call_center_sk, cc_county], file_type=parquet, predicate=cc_county@25 = Williamson County, pruning_predicate=cc_county_null_count@2 != row_count@3 AND cc_county_min@0 <= Williamson County AND Williamson County <= cc_county_max@1, required_guarantees=[cc_county in (Williamson County)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/call_center/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/call_center/part-3.parquet:..]]}, projection=[cc_call_center_sk, cc_county], file_type=parquet, predicate=cc_county@25 = Williamson County, pruning_predicate=cc_county_null_count@2 != row_count@3 AND cc_county_min@0 <= Williamson County AND Williamson County <= cc_county_max@1, required_guarantees=[cc_county in (Williamson County)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/call_center/part-3.parquet:..]]}, projection=[cc_call_center_sk, cc_county], file_type=parquet, predicate=cc_county@25 = Williamson County, pruning_predicate=cc_county_null_count@2 != row_count@3 AND cc_county_min@0 <= Williamson County AND Williamson County <= cc_county_max@1, required_guarantees=[cc_county in (Williamson County)] - └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: ca_state@1 = GA, projection=[ca_address_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = GA, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1, required_guarantees=[ca_state in (GA)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = GA, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1, required_guarantees=[ca_state in (GA)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = GA, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1, required_guarantees=[ca_state in (GA)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = GA, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1, required_guarantees=[ca_state in (GA)] - └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: d_date@1 >= 2002-02-01 AND d_date@1 <= 2002-04-02, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 2002-02-01 AND d_date@2 <= 2002-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 2002-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 2002-04-02, required_guarantees=[] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 2002-02-01 AND d_date@2 <= 2002-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 2002-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 2002-04-02, required_guarantees=[] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 2002-02-01 AND d_date@2 <= 2002-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 2002-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 2002-04-02, required_guarantees=[] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 2002-02-01 AND d_date@2 <= 2002-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 2002-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 2002-04-02, required_guarantees=[] + ┌───── Stage 8 ── tasks=4, partitions=6 + │ RepartitionExec: partitioning=Hash([alias1@0], 6), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[cs_order_number@0 as alias1], aggr=[sum(cs1.cs_ext_ship_cost) as alias2, sum(cs1.cs_net_profit) as alias3] + │ HashJoinExec: mode=Partitioned, join_type=LeftAnti, on=[(cs_order_number@0, cr_order_number@0)] + │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 7] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([cs_order_number@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(cs_order_number@1, cs_order_number@1)], filter=cs_warehouse_sk@0 != cs_warehouse_sk@1, projection=[cs_order_number@1, cs_ext_ship_cost@2, cs_net_profit@3] + │ [Stage 4] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([cs_order_number@1], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(cc_call_center_sk@0, cs_call_center_sk@0)], projection=[cs_warehouse_sk@2, cs_order_number@3, cs_ext_ship_cost@4, cs_net_profit@5] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, cs_ship_addr_sk@0)], projection=[cs_call_center_sk@2, cs_warehouse_sk@3, cs_order_number@4, cs_ext_ship_cost@5, cs_net_profit@6] + │ CoalescePartitionsExec + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, cs_ship_date_sk@0)], projection=[cs_ship_addr_sk@2, cs_call_center_sk@3, cs_warehouse_sk@4, cs_order_number@5, cs_ext_ship_cost@6, cs_net_profit@7] + │ CoalescePartitionsExec + │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..]]}, projection=[cs_ship_date_sk, cs_ship_addr_sk, cs_call_center_sk, cs_warehouse_sk, cs_order_number, cs_ext_ship_cost, cs_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_ship_date_sk, cs_ship_addr_sk, cs_call_center_sk, cs_warehouse_sk, cs_order_number, cs_ext_ship_cost, cs_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_ship_date_sk, cs_ship_addr_sk, cs_call_center_sk, cs_warehouse_sk, cs_order_number, cs_ext_ship_cost, cs_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_ship_date_sk, cs_ship_addr_sk, cs_call_center_sk, cs_warehouse_sk, cs_order_number, cs_ext_ship_cost, cs_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: cc_county@1 = Williamson County, projection=[cc_call_center_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/call_center/part-1.parquet:..]]}, projection=[cc_call_center_sk, cc_county], file_type=parquet, predicate=cc_county@25 = Williamson County, pruning_predicate=cc_county_null_count@2 != row_count@3 AND cc_county_min@0 <= Williamson County AND Williamson County <= cc_county_max@1, required_guarantees=[cc_county in (Williamson County)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/call_center/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/call_center/part-2.parquet:..]]}, projection=[cc_call_center_sk, cc_county], file_type=parquet, predicate=cc_county@25 = Williamson County, pruning_predicate=cc_county_null_count@2 != row_count@3 AND cc_county_min@0 <= Williamson County AND Williamson County <= cc_county_max@1, required_guarantees=[cc_county in (Williamson County)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/call_center/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/call_center/part-3.parquet:..]]}, projection=[cc_call_center_sk, cc_county], file_type=parquet, predicate=cc_county@25 = Williamson County, pruning_predicate=cc_county_null_count@2 != row_count@3 AND cc_county_min@0 <= Williamson County AND Williamson County <= cc_county_max@1, required_guarantees=[cc_county in (Williamson County)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/call_center/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/call_center/part-3.parquet:..]]}, projection=[cc_call_center_sk, cc_county], file_type=parquet, predicate=cc_county@25 = Williamson County, pruning_predicate=cc_county_null_count@2 != row_count@3 AND cc_county_min@0 <= Williamson County AND Williamson County <= cc_county_max@1, required_guarantees=[cc_county in (Williamson County)] + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: ca_state@1 = GA, projection=[ca_address_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = GA, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1, required_guarantees=[ca_state in (GA)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = GA, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1, required_guarantees=[ca_state in (GA)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = GA, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1, required_guarantees=[ca_state in (GA)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = GA, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1, required_guarantees=[ca_state in (GA)] + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_date@1 >= 2002-02-01 AND d_date@1 <= 2002-04-02, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 2002-02-01 AND d_date@2 <= 2002-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 2002-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 2002-04-02, required_guarantees=[] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 2002-02-01 AND d_date@2 <= 2002-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 2002-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 2002-04-02, required_guarantees=[] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 2002-02-01 AND d_date@2 <= 2002-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 2002-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 2002-04-02, required_guarantees=[] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 2002-02-01 AND d_date@2 <= 2002-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 2002-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 2002-04-02, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([cs_order_number@1], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..]]}, projection=[cs_warehouse_sk, cs_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_warehouse_sk, cs_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_warehouse_sk, cs_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_warehouse_sk, cs_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 7 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([cr_order_number@0], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:..]]}, projection=[cr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-3.parquet:..]]}, projection=[cr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-3.parquet:..]]}, projection=[cr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-3.parquet:..]]}, projection=[cr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── "); Ok(()) } @@ -4805,98 +4951,128 @@ mod tests { #[tokio::test] async fn test_tpcds_35() -> Result<()> { let display = test_tpcds_query("q35").await?; - assert_snapshot!(display, @r" + assert_snapshot!(display, @" ┌───── DistributedExec │ SortPreservingMergeExec: [ca_state@0 ASC, cd_gender@1 ASC, cd_marital_status@2 ASC, cd_dep_count@3 ASC, cd_dep_employed_count@8 ASC, cd_dep_college_count@13 ASC], fetch=100 │ SortExec: TopK(fetch=100), expr=[ca_state@0 ASC, cd_gender@1 ASC, cd_marital_status@2 ASC, cd_dep_count@3 ASC, cd_dep_employed_count@8 ASC, cd_dep_college_count@13 ASC], preserve_partitioning=[true] │ ProjectionExec: expr=[ca_state@0 as ca_state, cd_gender@1 as cd_gender, cd_marital_status@2 as cd_marital_status, cd_dep_count@3 as cd_dep_count, count(Int64(1))@6 as cnt1, min(customer_demographics.cd_dep_count)@7 as min1, max(customer_demographics.cd_dep_count)@8 as max1, avg(customer_demographics.cd_dep_count)@9 as avg1, cd_dep_employed_count@4 as cd_dep_employed_count, count(Int64(1))@6 as cnt2, min(customer_demographics.cd_dep_employed_count)@10 as min2, max(customer_demographics.cd_dep_employed_count)@11 as max2, avg(customer_demographics.cd_dep_employed_count)@12 as avg2, cd_dep_college_count@5 as cd_dep_college_count, count(Int64(1))@6 as cnt3, min(customer_demographics.cd_dep_college_count)@13 as min(customer_demographics.cd_dep_college_count), max(customer_demographics.cd_dep_college_count)@14 as max(customer_demographics.cd_dep_college_count), avg(customer_demographics.cd_dep_college_count)@15 as avg(customer_demographics.cd_dep_college_count)] │ AggregateExec: mode=FinalPartitioned, gby=[ca_state@0 as ca_state, cd_gender@1 as cd_gender, cd_marital_status@2 as cd_marital_status, cd_dep_count@3 as cd_dep_count, cd_dep_employed_count@4 as cd_dep_employed_count, cd_dep_college_count@5 as cd_dep_college_count], aggr=[count(Int64(1)), min(customer_demographics.cd_dep_count), max(customer_demographics.cd_dep_count), avg(customer_demographics.cd_dep_count), min(customer_demographics.cd_dep_employed_count), max(customer_demographics.cd_dep_employed_count), avg(customer_demographics.cd_dep_employed_count), min(customer_demographics.cd_dep_college_count), max(customer_demographics.cd_dep_college_count), avg(customer_demographics.cd_dep_college_count)] - │ RepartitionExec: partitioning=Hash([ca_state@0, cd_gender@1, cd_marital_status@2, cd_dep_count@3, cd_dep_employed_count@4, cd_dep_college_count@5], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[ca_state@0 as ca_state, cd_gender@1 as cd_gender, cd_marital_status@2 as cd_marital_status, cd_dep_count@3 as cd_dep_count, cd_dep_employed_count@4 as cd_dep_employed_count, cd_dep_college_count@5 as cd_dep_college_count], aggr=[count(Int64(1)), min(customer_demographics.cd_dep_count), max(customer_demographics.cd_dep_count), avg(customer_demographics.cd_dep_count), min(customer_demographics.cd_dep_employed_count), max(customer_demographics.cd_dep_employed_count), avg(customer_demographics.cd_dep_employed_count), min(customer_demographics.cd_dep_college_count), max(customer_demographics.cd_dep_college_count), avg(customer_demographics.cd_dep_college_count)] - │ FilterExec: mark@6 OR mark@7, projection=[ca_state@0, cd_gender@1, cd_marital_status@2, cd_dep_count@3, cd_dep_employed_count@4, cd_dep_college_count@5] - │ HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(c_customer_sk@0, cs_ship_customer_sk@0)], projection=[ca_state@1, cd_gender@2, cd_marital_status@3, cd_dep_count@4, cd_dep_employed_count@5, cd_dep_college_count@6, mark@7, mark@8] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftMark, on=[(c_customer_sk@0, ws_bill_customer_sk@0)] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(c_customer_sk@0, ss_customer_sk@0)] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ss_sold_date_sk@0)], projection=[ss_customer_sk@2] - │ CoalescePartitionsExec - │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_sold_date_sk@0)], projection=[ws_bill_customer_sk@2] - │ CoalescePartitionsExec - │ [Stage 5] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, cs_sold_date_sk@0)], projection=[cs_ship_customer_sk@2] - │ CoalescePartitionsExec - │ [Stage 6] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ [Stage 12] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(c_current_cdemo_sk@1, cd_demo_sk@0)], projection=[c_customer_sk@0, ca_state@2, cd_gender@4, cd_marital_status@5, cd_dep_count@6, cd_dep_employed_count@7, cd_dep_college_count@8] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] + ┌───── Stage 12 ── tasks=4, partitions=3 + │ RepartitionExec: partitioning=Hash([ca_state@0, cd_gender@1, cd_marital_status@2, cd_dep_count@3, cd_dep_employed_count@4, cd_dep_college_count@5], 3), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[ca_state@0 as ca_state, cd_gender@1 as cd_gender, cd_marital_status@2 as cd_marital_status, cd_dep_count@3 as cd_dep_count, cd_dep_employed_count@4 as cd_dep_employed_count, cd_dep_college_count@5 as cd_dep_college_count], aggr=[count(Int64(1)), min(customer_demographics.cd_dep_count), max(customer_demographics.cd_dep_count), avg(customer_demographics.cd_dep_count), min(customer_demographics.cd_dep_employed_count), max(customer_demographics.cd_dep_employed_count), avg(customer_demographics.cd_dep_employed_count), min(customer_demographics.cd_dep_college_count), max(customer_demographics.cd_dep_college_count), avg(customer_demographics.cd_dep_college_count)] + │ FilterExec: mark@6 OR mark@7, projection=[ca_state@0, cd_gender@1, cd_marital_status@2, cd_dep_count@3, cd_dep_employed_count@4, cd_dep_college_count@5] + │ HashJoinExec: mode=Partitioned, join_type=LeftMark, on=[(c_customer_sk@0, cs_ship_customer_sk@0)], projection=[ca_state@1, cd_gender@2, cd_marital_status@3, cd_dep_count@4, cd_dep_employed_count@5, cd_dep_college_count@6, mark@7, mark@8] + │ [Stage 9] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 11] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, c_current_addr_sk@2)], projection=[c_customer_sk@2, c_current_cdemo_sk@3, ca_state@1] + ┌───── Stage 9 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftMark, on=[(c_customer_sk@0, ws_bill_customer_sk@0)] + │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 8] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(c_customer_sk@0, ss_customer_sk@0)] + │ [Stage 3] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(c_current_cdemo_sk@1, cd_demo_sk@0)], projection=[c_customer_sk@0, ca_state@2, cd_gender@4, cd_marital_status@5, cd_dep_count@6, cd_dep_employed_count@7, cd_dep_college_count@8] + │ CoalescePartitionsExec + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_dep_count, cd_dep_employed_count, cd_dep_college_count], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, c_current_addr_sk@2)], projection=[c_customer_sk@2, c_current_cdemo_sk@3, ca_state@1] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=32 + │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ss_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ss_sold_date_sk@0)], projection=[ss_customer_sk@2] + │ CoalescePartitionsExec + │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_year@1 = 2002 AND d_qoy@2 < 4, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + └────────────────────────────────────────────────── + ┌───── Stage 8 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_bill_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_sold_date_sk@0)], projection=[ws_bill_customer_sk@2] + │ CoalescePartitionsExec + │ [Stage 7] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 7 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_year@1 = 2002 AND d_qoy@2 < 4, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + └────────────────────────────────────────────────── + ┌───── Stage 11 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([cs_ship_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, cs_sold_date_sk@0)], projection=[cs_ship_customer_sk@2] │ CoalescePartitionsExec - │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ [Stage 10] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=32 - │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet + ┌───── Stage 10 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_year@1 = 2002 AND d_qoy@2 < 4, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_year@1 = 2002 AND d_qoy@2 < 4, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - └────────────────────────────────────────────────── - ┌───── Stage 5 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_year@1 = 2002 AND d_qoy@2 < 4, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - └────────────────────────────────────────────────── - ┌───── Stage 6 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_year@1 = 2002 AND d_qoy@2 < 4, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_qoy], file_type=parquet, predicate=d_year@6 = 2002 AND d_qoy@10 < 4, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2002 AND 2002 <= d_year_max@1 AND d_qoy_null_count@5 != row_count@3 AND d_qoy_min@4 < 4, required_guarantees=[d_year in (2002)] - └────────────────────────────────────────────────── "); Ok(()) } @@ -8993,100 +9169,133 @@ mod tests { } #[tokio::test] async fn test_tpcds_69() -> Result<()> { - let display = test_tpcds_query("q69").await?; - assert_snapshot!(display, @r" - ┌───── DistributedExec - │ SortPreservingMergeExec: [cd_gender@0 ASC NULLS LAST, cd_marital_status@1 ASC NULLS LAST, cd_education_status@2 ASC NULLS LAST, cd_purchase_estimate@4 ASC NULLS LAST, cd_credit_rating@6 ASC NULLS LAST], fetch=100 - │ SortExec: TopK(fetch=100), expr=[cd_gender@0 ASC NULLS LAST, cd_marital_status@1 ASC NULLS LAST, cd_education_status@2 ASC NULLS LAST, cd_purchase_estimate@4 ASC NULLS LAST, cd_credit_rating@6 ASC NULLS LAST], preserve_partitioning=[true] - │ ProjectionExec: expr=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, count(Int64(1))@5 as cnt1, cd_purchase_estimate@3 as cd_purchase_estimate, count(Int64(1))@5 as cnt2, cd_credit_rating@4 as cd_credit_rating, count(Int64(1))@5 as cnt3] - │ AggregateExec: mode=FinalPartitioned, gby=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, cd_purchase_estimate@3 as cd_purchase_estimate, cd_credit_rating@4 as cd_credit_rating], aggr=[count(Int64(1))] - │ RepartitionExec: partitioning=Hash([cd_gender@0, cd_marital_status@1, cd_education_status@2, cd_purchase_estimate@3, cd_credit_rating@4], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, cd_purchase_estimate@3 as cd_purchase_estimate, cd_credit_rating@4 as cd_credit_rating], aggr=[count(Int64(1))] - │ HashJoinExec: mode=CollectLeft, join_type=LeftAnti, on=[(c_customer_sk@0, cs_ship_customer_sk@0)], projection=[cd_gender@1, cd_marital_status@2, cd_education_status@3, cd_purchase_estimate@4, cd_credit_rating@5] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftAnti, on=[(c_customer_sk@0, ws_bill_customer_sk@0)] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(c_customer_sk@0, ss_customer_sk@0)] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ss_sold_date_sk@0)], projection=[ss_customer_sk@2] - │ CoalescePartitionsExec - │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_sold_date_sk@0)], projection=[ws_bill_customer_sk@2] - │ CoalescePartitionsExec - │ [Stage 5] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, cs_sold_date_sk@0)], projection=[cs_ship_customer_sk@2] - │ CoalescePartitionsExec - │ [Stage 6] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(c_current_cdemo_sk@1, cd_demo_sk@0)], projection=[c_customer_sk@0, cd_gender@3, cd_marital_status@4, cd_education_status@5, cd_purchase_estimate@6, cd_credit_rating@7] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, c_current_addr_sk@2)], projection=[c_customer_sk@1, c_current_cdemo_sk@2] - │ CoalescePartitionsExec - │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] - └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: ca_state@1 = KY OR ca_state@1 = GA OR ca_state@1 = NM, projection=[ca_address_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = KY OR ca_state@8 = GA OR ca_state@8 = NM, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= KY AND KY <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= NM AND NM <= ca_state_max@1, required_guarantees=[ca_state in (GA, KY, NM)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = KY OR ca_state@8 = GA OR ca_state@8 = NM, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= KY AND KY <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= NM AND NM <= ca_state_max@1, required_guarantees=[ca_state in (GA, KY, NM)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = KY OR ca_state@8 = GA OR ca_state@8 = NM, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= KY AND KY <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= NM AND NM <= ca_state_max@1, required_guarantees=[ca_state in (GA, KY, NM)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = KY OR ca_state@8 = GA OR ca_state@8 = NM, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= KY AND KY <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= NM AND NM <= ca_state_max@1, required_guarantees=[ca_state in (GA, KY, NM)] - └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_year@1 = 2001 AND d_moy@2 >= 4 AND d_moy@2 <= 6, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - └────────────────────────────────────────────────── - ┌───── Stage 5 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_year@1 = 2001 AND d_moy@2 >= 4 AND d_moy@2 <= 6, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - └────────────────────────────────────────────────── - ┌───── Stage 6 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_year@1 = 2001 AND d_moy@2 >= 4 AND d_moy@2 <= 6, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + let display = test_tpcds_query("q69").await?; + assert_snapshot!(display, @" + ┌───── DistributedExec + │ SortPreservingMergeExec: [cd_gender@0 ASC NULLS LAST, cd_marital_status@1 ASC NULLS LAST, cd_education_status@2 ASC NULLS LAST, cd_purchase_estimate@4 ASC NULLS LAST, cd_credit_rating@6 ASC NULLS LAST], fetch=100 + │ [Stage 13] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 + └────────────────────────────────────────────────── + ┌───── Stage 13 ── tasks=2, partitions=3 + │ SortExec: TopK(fetch=100), expr=[cd_gender@0 ASC NULLS LAST, cd_marital_status@1 ASC NULLS LAST, cd_education_status@2 ASC NULLS LAST, cd_purchase_estimate@4 ASC NULLS LAST, cd_credit_rating@6 ASC NULLS LAST], preserve_partitioning=[true] + │ ProjectionExec: expr=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, count(Int64(1))@5 as cnt1, cd_purchase_estimate@3 as cd_purchase_estimate, count(Int64(1))@5 as cnt2, cd_credit_rating@4 as cd_credit_rating, count(Int64(1))@5 as cnt3] + │ AggregateExec: mode=FinalPartitioned, gby=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, cd_purchase_estimate@3 as cd_purchase_estimate, cd_credit_rating@4 as cd_credit_rating], aggr=[count(Int64(1))] + │ [Stage 12] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── + ┌───── Stage 12 ── tasks=4, partitions=6 + │ RepartitionExec: partitioning=Hash([cd_gender@0, cd_marital_status@1, cd_education_status@2, cd_purchase_estimate@3, cd_credit_rating@4], 6), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[cd_gender@0 as cd_gender, cd_marital_status@1 as cd_marital_status, cd_education_status@2 as cd_education_status, cd_purchase_estimate@3 as cd_purchase_estimate, cd_credit_rating@4 as cd_credit_rating], aggr=[count(Int64(1))] + │ HashJoinExec: mode=Partitioned, join_type=LeftAnti, on=[(c_customer_sk@0, cs_ship_customer_sk@0)], projection=[cd_gender@1, cd_marital_status@2, cd_education_status@3, cd_purchase_estimate@4, cd_credit_rating@5] + │ [Stage 9] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 11] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 9 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftAnti, on=[(c_customer_sk@0, ws_bill_customer_sk@0)] + │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 8] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(c_customer_sk@0, ss_customer_sk@0)] + │ [Stage 3] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(c_current_cdemo_sk@1, cd_demo_sk@0)], projection=[c_customer_sk@0, cd_gender@3, cd_marital_status@4, cd_education_status@5, cd_purchase_estimate@6, cd_credit_rating@7] + │ CoalescePartitionsExec + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_demographics/part-3.parquet:..]]}, projection=[cd_demo_sk, cd_gender, cd_marital_status, cd_education_status, cd_purchase_estimate, cd_credit_rating], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, c_current_addr_sk@2)], projection=[c_customer_sk@1, c_current_cdemo_sk@2] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer/part-3.parquet:..]]}, projection=[c_customer_sk, c_current_cdemo_sk, c_current_addr_sk], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: ca_state@1 = KY OR ca_state@1 = GA OR ca_state@1 = NM, projection=[ca_address_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = KY OR ca_state@8 = GA OR ca_state@8 = NM, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= KY AND KY <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= NM AND NM <= ca_state_max@1, required_guarantees=[ca_state in (GA, KY, NM)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = KY OR ca_state@8 = GA OR ca_state@8 = NM, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= KY AND KY <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= NM AND NM <= ca_state_max@1, required_guarantees=[ca_state in (GA, KY, NM)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = KY OR ca_state@8 = GA OR ca_state@8 = NM, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= KY AND KY <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= NM AND NM <= ca_state_max@1, required_guarantees=[ca_state in (GA, KY, NM)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = KY OR ca_state@8 = GA OR ca_state@8 = NM, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= KY AND KY <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= GA AND GA <= ca_state_max@1 OR ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= NM AND NM <= ca_state_max@1, required_guarantees=[ca_state in (GA, KY, NM)] + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ss_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ss_sold_date_sk@0)], projection=[ss_customer_sk@2] + │ CoalescePartitionsExec + │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_sales/part-3.parquet:..]]}, projection=[ss_sold_date_sk, ss_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_year@1 = 2001 AND d_moy@2 >= 4 AND d_moy@2 <= 6, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + └────────────────────────────────────────────────── + ┌───── Stage 8 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_bill_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_sold_date_sk@0)], projection=[ws_bill_customer_sk@2] + │ CoalescePartitionsExec + │ [Stage 7] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_sold_date_sk, ws_bill_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 7 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_year@1 = 2001 AND d_moy@2 >= 4 AND d_moy@2 <= 6, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + └────────────────────────────────────────────────── + ┌───── Stage 11 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([cs_ship_customer_sk@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, cs_sold_date_sk@0)], projection=[cs_ship_customer_sk@2] + │ CoalescePartitionsExec + │ [Stage 10] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_sales/part-3.parquet:..]]}, projection=[cs_sold_date_sk, cs_ship_customer_sk], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 10 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_year@1 = 2001 AND d_moy@2 >= 4 AND d_moy@2 <= 6, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_year, d_moy], file_type=parquet, predicate=d_year@6 = 2001 AND d_moy@8 >= 4 AND d_moy@8 <= 6, pruning_predicate=d_year_null_count@2 != row_count@3 AND d_year_min@0 <= 2001 AND 2001 <= d_year_max@1 AND d_moy_null_count@5 != row_count@3 AND d_moy_max@4 >= 4 AND d_moy_null_count@5 != row_count@3 AND d_moy_min@6 <= 6, required_guarantees=[d_year in (2001)] + └────────────────────────────────────────────────── "); Ok(()) } @@ -10996,106 +11205,116 @@ mod tests { #[tokio::test] async fn test_tpcds_83() -> Result<()> { let display = test_tpcds_query("q83").await?; - assert_snapshot!(display, @r" + assert_snapshot!(display, @" ┌───── DistributedExec │ SortPreservingMergeExec: [item_id@0 ASC], fetch=100 - │ [Stage 16] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 + │ [Stage 18] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 └────────────────────────────────────────────────── - ┌───── Stage 16 ── tasks=2, partitions=3 + ┌───── Stage 18 ── tasks=2, partitions=3 │ SortExec: TopK(fetch=100), expr=[item_id@0 ASC], preserve_partitioning=[true] │ ProjectionExec: expr=[item_id@1 as item_id, sr_item_qty@2 as sr_item_qty, CAST(sr_item_qty@2 AS Float64) / __common_expr_7@0 / 3 * 100 as sr_dev, cr_item_qty@3 as cr_item_qty, CAST(cr_item_qty@3 AS Float64) / __common_expr_7@0 / 3 * 100 as cr_dev, wr_item_qty@4 as wr_item_qty, CAST(wr_item_qty@4 AS Float64) / __common_expr_7@0 / 3 * 100 as wr_dev, __common_expr_7@0 / 3 as average] │ ProjectionExec: expr=[CAST(sr_item_qty@0 + cr_item_qty@1 + wr_item_qty@2 AS Float64) as __common_expr_7, item_id@3 as item_id, sr_item_qty@0 as sr_item_qty, cr_item_qty@1 as cr_item_qty, wr_item_qty@2 as wr_item_qty] │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(item_id@0, item_id@0)], projection=[sr_item_qty@3, cr_item_qty@4, wr_item_qty@1, item_id@2] │ CoalescePartitionsExec - │ [Stage 5] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=6, input_tasks=1 + │ [Stage 7] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=6, input_tasks=2 │ HashJoinExec: mode=Partitioned, join_type=Inner, on=[(item_id@0, item_id@0)], projection=[item_id@2, sr_item_qty@3, cr_item_qty@1] │ ProjectionExec: expr=[i_item_id@0 as item_id, sum(catalog_returns.cr_return_quantity)@1 as cr_item_qty] │ AggregateExec: mode=FinalPartitioned, gby=[i_item_id@0 as i_item_id], aggr=[sum(catalog_returns.cr_return_quantity)] - │ [Stage 10] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 12] => NetworkShuffleExec: output_partitions=3, input_tasks=4 │ ProjectionExec: expr=[i_item_id@0 as item_id, sum(store_returns.sr_return_quantity)@1 as sr_item_qty] │ AggregateExec: mode=FinalPartitioned, gby=[i_item_id@0 as i_item_id], aggr=[sum(store_returns.sr_return_quantity)] - │ [Stage 15] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 17] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 5 ── tasks=1, partitions=6 + ┌───── Stage 7 ── tasks=2, partitions=12 │ BroadcastExec: input_partitions=3, consumer_tasks=2, output_partitions=6 │ ProjectionExec: expr=[i_item_id@0 as item_id, sum(web_returns.wr_return_quantity)@1 as wr_item_qty] │ AggregateExec: mode=FinalPartitioned, gby=[i_item_id@0 as i_item_id], aggr=[sum(web_returns.wr_return_quantity)] - │ RepartitionExec: partitioning=Hash([i_item_id@0], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[i_item_id@1 as i_item_id], aggr=[sum(web_returns.wr_return_quantity)] - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(d_date@2, d_date@0)], projection=[wr_return_quantity@0, i_item_id@1] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=RightSemi, on=[(d_week_seq@0, d_week_seq@1)], projection=[d_date@0] - │ CoalescePartitionsExec - │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(wr_returned_date_sk@0, d_date_sk@0)], projection=[wr_return_quantity@1, i_item_id@2, d_date@4] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] + ┌───── Stage 6 ── tasks=4, partitions=6 + │ RepartitionExec: partitioning=Hash([i_item_id@0], 6), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[i_item_id@1 as i_item_id], aggr=[sum(web_returns.wr_return_quantity)] + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(d_date@2, d_date@0)], projection=[wr_return_quantity@0, i_item_id@1] + │ [Stage 3] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(i_item_sk@0, wr_item_sk@1)], projection=[wr_returned_date_sk@2, wr_return_quantity@4, i_item_id@1] + ┌───── Stage 3 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([d_date@2], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(wr_returned_date_sk@0, d_date_sk@0)], projection=[wr_return_quantity@1, i_item_id@2, d_date@4] │ CoalescePartitionsExec - │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_returned_date_sk, wr_item_sk, wr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_returned_date_sk, wr_item_sk, wr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_returned_date_sk, wr_item_sk, wr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_returned_date_sk, wr_item_sk, wr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=32 - │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/item/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/item/part-3.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet + ┌───── Stage 2 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(i_item_sk@0, wr_item_sk@1)], projection=[wr_returned_date_sk@2, wr_return_quantity@4, i_item_id@1] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_returned_date_sk, wr_item_sk, wr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_returned_date_sk, wr_item_sk, wr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_returned_date_sk, wr_item_sk, wr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_returned_date_sk, wr_item_sk, wr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ FilterExec: d_date@0 = 2000-06-30 OR d_date@0 = 2000-09-27 OR d_date@0 = 2000-11-17, projection=[d_week_seq@1] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] - └────────────────────────────────────────────────── - ┌───── Stage 10 ── tasks=4, partitions=6 + ┌───── Stage 1 ── tasks=4, partitions=32 + │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/item/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/item/part-3.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([d_date@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=RightSemi, on=[(d_week_seq@0, d_week_seq@1)], projection=[d_date@0] + │ CoalescePartitionsExec + │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_date@0 = 2000-06-30 OR d_date@0 = 2000-09-27 OR d_date@0 = 2000-11-17, projection=[d_week_seq@1] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] + └────────────────────────────────────────────────── + ┌───── Stage 12 ── tasks=4, partitions=6 │ RepartitionExec: partitioning=Hash([i_item_id@0], 6), input_partitions=3 │ AggregateExec: mode=Partial, gby=[i_item_id@1 as i_item_id], aggr=[sum(catalog_returns.cr_return_quantity)] │ HashJoinExec: mode=CollectLeft, join_type=RightSemi, on=[(d_date@0, d_date@2)], projection=[cr_return_quantity@0, i_item_id@1] │ CoalescePartitionsExec - │ [Stage 7] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ [Stage 9] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, cr_returned_date_sk@0)], projection=[cr_return_quantity@3, i_item_id@4, d_date@1] │ CoalescePartitionsExec - │ [Stage 8] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 + │ [Stage 10] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(i_item_sk@0, cr_item_sk@1)], projection=[cr_returned_date_sk@2, cr_return_quantity@4, i_item_id@1] │ CoalescePartitionsExec - │ [Stage 9] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 + │ [Stage 11] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:..]]}, projection=[cr_returned_date_sk, cr_item_sk, cr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-3.parquet:..]]}, projection=[cr_returned_date_sk, cr_item_sk, cr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-3.parquet:..]]}, projection=[cr_returned_date_sk, cr_item_sk, cr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/catalog_returns/part-3.parquet:..]]}, projection=[cr_returned_date_sk, cr_item_sk, cr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 7 ── tasks=4, partitions=48 + ┌───── Stage 9 ── tasks=4, partitions=48 │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 │ HashJoinExec: mode=CollectLeft, join_type=RightSemi, on=[(d_week_seq@0, d_week_seq@1)], projection=[d_date@0] │ CoalescePartitionsExec - │ [Stage 6] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ [Stage 8] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] @@ -11103,7 +11322,7 @@ mod tests { │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 6 ── tasks=4, partitions=48 + ┌───── Stage 8 ── tasks=4, partitions=48 │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 │ FilterExec: d_date@0 = 2000-06-30 OR d_date@0 = 2000-09-27 OR d_date@0 = 2000-11-17, projection=[d_week_seq@1] │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 @@ -11113,7 +11332,7 @@ mod tests { │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] └────────────────────────────────────────────────── - ┌───── Stage 8 ── tasks=4, partitions=32 + ┌───── Stage 10 ── tasks=4, partitions=32 │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] @@ -11121,7 +11340,7 @@ mod tests { │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 9 ── tasks=4, partitions=32 + ┌───── Stage 11 ── tasks=4, partitions=32 │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet @@ -11129,29 +11348,29 @@ mod tests { │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/item/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/item/part-3.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet └────────────────────────────────────────────────── - ┌───── Stage 15 ── tasks=4, partitions=6 + ┌───── Stage 17 ── tasks=4, partitions=6 │ RepartitionExec: partitioning=Hash([i_item_id@0], 6), input_partitions=3 │ AggregateExec: mode=Partial, gby=[i_item_id@1 as i_item_id], aggr=[sum(store_returns.sr_return_quantity)] │ HashJoinExec: mode=CollectLeft, join_type=RightSemi, on=[(d_date@0, d_date@2)], projection=[sr_return_quantity@0, i_item_id@1] │ CoalescePartitionsExec - │ [Stage 12] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ [Stage 14] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, sr_returned_date_sk@0)], projection=[sr_return_quantity@3, i_item_id@4, d_date@1] │ CoalescePartitionsExec - │ [Stage 13] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 + │ [Stage 15] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(i_item_sk@0, sr_item_sk@1)], projection=[sr_returned_date_sk@2, sr_return_quantity@4, i_item_id@1] │ CoalescePartitionsExec - │ [Stage 14] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 + │ [Stage 16] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_returns/part-2.parquet:..]]}, projection=[sr_returned_date_sk, sr_item_sk, sr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_returns/part-3.parquet:..]]}, projection=[sr_returned_date_sk, sr_item_sk, sr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_returns/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_returns/part-3.parquet:..]]}, projection=[sr_returned_date_sk, sr_item_sk, sr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/store_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/store_returns/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/store_returns/part-3.parquet:..]]}, projection=[sr_returned_date_sk, sr_item_sk, sr_return_quantity], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 12 ── tasks=4, partitions=48 + ┌───── Stage 14 ── tasks=4, partitions=48 │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 │ HashJoinExec: mode=CollectLeft, join_type=RightSemi, on=[(d_week_seq@0, d_week_seq@1)], projection=[d_date@0] │ CoalescePartitionsExec - │ [Stage 11] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ [Stage 13] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] @@ -11159,7 +11378,7 @@ mod tests { │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 11 ── tasks=4, partitions=48 + ┌───── Stage 13 ── tasks=4, partitions=48 │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 │ FilterExec: d_date@0 = 2000-06-30 OR d_date@0 = 2000-09-27 OR d_date@0 = 2000-11-17, projection=[d_week_seq@1] │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 @@ -11169,7 +11388,7 @@ mod tests { │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date, d_week_seq], file_type=parquet, predicate=d_date@2 = 2000-06-30 OR d_date@2 = 2000-09-27 OR d_date@2 = 2000-11-17, pruning_predicate=d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-06-30 AND 2000-06-30 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-09-27 AND 2000-09-27 <= d_date_max@1 OR d_date_null_count@2 != row_count@3 AND d_date_min@0 <= 2000-11-17 AND 2000-11-17 <= d_date_max@1, required_guarantees=[d_date in (2000-06-30, 2000-09-27, 2000-11-17)] └────────────────────────────────────────────────── - ┌───── Stage 13 ── tasks=4, partitions=32 + ┌───── Stage 15 ── tasks=4, partitions=32 │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] @@ -11177,7 +11396,7 @@ mod tests { │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 14 ── tasks=4, partitions=32 + ┌───── Stage 16 ── tasks=4, partitions=32 │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 │ DistributedLeafExec: │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/item/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/item/part-1.parquet:..]]}, projection=[i_item_sk, i_item_id], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] @@ -12422,190 +12641,230 @@ mod tests { #[tokio::test] async fn test_tpcds_94() -> Result<()> { let display = test_tpcds_query("q94").await?; - assert_snapshot!(display, @r" + assert_snapshot!(display, @" ┌───── DistributedExec │ ProjectionExec: expr=[count(alias1)@0 as order count, sum(alias2)@1 as total shipping cost, sum(alias3)@2 as total net profit] │ GlobalLimitExec: skip=0, fetch=100 │ AggregateExec: mode=Final, gby=[], aggr=[count(alias1), sum(alias2), sum(alias3)] │ CoalescePartitionsExec - │ AggregateExec: mode=Partial, gby=[], aggr=[count(alias1), sum(alias2), sum(alias3)] - │ AggregateExec: mode=FinalPartitioned, gby=[alias1@0 as alias1], aggr=[sum(ws1.ws_ext_ship_cost) as alias2, sum(ws1.ws_net_profit) as alias3] - │ RepartitionExec: partitioning=Hash([alias1@0], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[ws_order_number@0 as alias1], aggr=[sum(ws1.ws_ext_ship_cost) as alias2, sum(ws1.ws_net_profit) as alias3] - │ HashJoinExec: mode=CollectLeft, join_type=LeftAnti, on=[(ws_order_number@0, wr_order_number@0)] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(ws_order_number@1, ws_order_number@1)], filter=ws_warehouse_sk@0 != ws_warehouse_sk@1, projection=[ws_order_number@1, ws_ext_ship_cost@2, ws_net_profit@3] - │ CoalescePartitionsExec - │ [Stage 4] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ [Stage 9] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(web_site_sk@0, ws_web_site_sk@0)], projection=[ws_warehouse_sk@2, ws_order_number@3, ws_ext_ship_cost@4, ws_net_profit@5] - │ CoalescePartitionsExec - │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, ws_ship_addr_sk@0)], projection=[ws_web_site_sk@2, ws_warehouse_sk@3, ws_order_number@4, ws_ext_ship_cost@5, ws_net_profit@6] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_ship_date_sk@0)], projection=[ws_ship_addr_sk@2, ws_web_site_sk@3, ws_warehouse_sk@4, ws_order_number@5, ws_ext_ship_cost@6, ws_net_profit@7] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_warehouse_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_warehouse_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_warehouse_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_warehouse_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + ┌───── Stage 9 ── tasks=2, partitions=3 + │ AggregateExec: mode=Partial, gby=[], aggr=[count(alias1), sum(alias2), sum(alias3)] + │ AggregateExec: mode=FinalPartitioned, gby=[alias1@0 as alias1], aggr=[sum(ws1.ws_ext_ship_cost) as alias2, sum(ws1.ws_net_profit) as alias3] + │ [Stage 8] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: web_company_name@1 = pri, projection=[web_site_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-1.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-2.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-3.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-3.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] - └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: ca_state@1 = IL, projection=[ca_address_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] - └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: d_date@1 >= 1999-02-01 AND d_date@1 <= 1999-04-02, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] + ┌───── Stage 8 ── tasks=4, partitions=6 + │ RepartitionExec: partitioning=Hash([alias1@0], 6), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[ws_order_number@0 as alias1], aggr=[sum(ws1.ws_ext_ship_cost) as alias2, sum(ws1.ws_net_profit) as alias3] + │ HashJoinExec: mode=Partitioned, join_type=LeftAnti, on=[(ws_order_number@0, wr_order_number@0)] + │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 7] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(ws_order_number@1, ws_order_number@1)], filter=ws_warehouse_sk@0 != ws_warehouse_sk@1, projection=[ws_order_number@1, ws_ext_ship_cost@2, ws_net_profit@3] + │ [Stage 4] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@1], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(web_site_sk@0, ws_web_site_sk@0)], projection=[ws_warehouse_sk@2, ws_order_number@3, ws_ext_ship_cost@4, ws_net_profit@5] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, ws_ship_addr_sk@0)], projection=[ws_web_site_sk@2, ws_warehouse_sk@3, ws_order_number@4, ws_ext_ship_cost@5, ws_net_profit@6] + │ CoalescePartitionsExec + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_ship_date_sk@0)], projection=[ws_ship_addr_sk@2, ws_web_site_sk@3, ws_warehouse_sk@4, ws_order_number@5, ws_ext_ship_cost@6, ws_net_profit@7] + │ CoalescePartitionsExec + │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_warehouse_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_warehouse_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_warehouse_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_warehouse_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: web_company_name@1 = pri, projection=[web_site_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-1.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-2.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-3.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-3.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: ca_state@1 = IL, projection=[ca_address_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_date@1 >= 1999-02-01 AND d_date@1 <= 1999-04-02, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@1], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 7 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([wr_order_number@0], 12), input_partitions=3 + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── "); Ok(()) } #[tokio::test] async fn test_tpcds_95() -> Result<()> { let display = test_tpcds_query("q95").await?; - assert_snapshot!(display, @r" + assert_snapshot!(display, @" ┌───── DistributedExec │ ProjectionExec: expr=[count(alias1)@0 as order count, sum(alias2)@1 as total shipping cost, sum(alias3)@2 as total net profit] │ GlobalLimitExec: skip=0, fetch=100 │ AggregateExec: mode=Final, gby=[], aggr=[count(alias1), sum(alias2), sum(alias3)] │ CoalescePartitionsExec - │ AggregateExec: mode=Partial, gby=[], aggr=[count(alias1), sum(alias2), sum(alias3)] - │ AggregateExec: mode=FinalPartitioned, gby=[alias1@0 as alias1], aggr=[sum(ws1.ws_ext_ship_cost) as alias2, sum(ws1.ws_net_profit) as alias3] - │ RepartitionExec: partitioning=Hash([alias1@0], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[ws_order_number@0 as alias1], aggr=[sum(ws1.ws_ext_ship_cost) as alias2, sum(ws1.ws_net_profit) as alias3] - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(ws_order_number@0, wr_order_number@0)] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(ws_order_number@0, ws_order_number@0)] - │ CoalescePartitionsExec - │ [Stage 4] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ HashJoinExec: mode=Partitioned, join_type=Inner, on=[(ws_order_number@1, ws_order_number@1)], filter=ws_warehouse_sk@1 != ws_warehouse_sk@0, projection=[ws_order_number@1] - │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 - │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(wr_order_number@0, ws_order_number@0)], projection=[wr_order_number@0] - │ CoalescePartitionsExec - │ [Stage 7] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=2, input_tasks=4 - │ HashJoinExec: mode=Partitioned, join_type=Inner, on=[(ws_order_number@1, ws_order_number@1)], filter=ws_warehouse_sk@1 != ws_warehouse_sk@0, projection=[ws_order_number@1] - │ [Stage 8] => NetworkShuffleExec: output_partitions=3, input_tasks=4 - │ [Stage 9] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 14] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(web_site_sk@0, ws_web_site_sk@0)], projection=[ws_order_number@2, ws_ext_ship_cost@3, ws_net_profit@4] - │ CoalescePartitionsExec - │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, ws_ship_addr_sk@0)], projection=[ws_web_site_sk@2, ws_order_number@3, ws_ext_ship_cost@4, ws_net_profit@5] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_ship_date_sk@0)], projection=[ws_ship_addr_sk@2, ws_web_site_sk@3, ws_order_number@4, ws_ext_ship_cost@5, ws_net_profit@6] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: web_company_name@1 = pri, projection=[web_site_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-1.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-2.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-3.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-3.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] - └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: ca_state@1 = IL, projection=[ca_address_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] - └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: d_date@1 >= 1999-02-01 AND d_date@1 <= 1999-04-02, projection=[d_date_sk@0] - │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] - └────────────────────────────────────────────────── - ┌───── Stage 5 ── tasks=4, partitions=3 - │ RepartitionExec: partitioning=Hash([ws_order_number@1], 3), input_partitions=3 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - └────────────────────────────────────────────────── - ┌───── Stage 6 ── tasks=4, partitions=3 - │ RepartitionExec: partitioning=Hash([ws_order_number@1], 3), input_partitions=3 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - └────────────────────────────────────────────────── - ┌───── Stage 7 ── tasks=4, partitions=8 - │ BroadcastExec: input_partitions=2, consumer_tasks=1, output_partitions=2 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - └────────────────────────────────────────────────── - ┌───── Stage 8 ── tasks=4, partitions=3 - │ RepartitionExec: partitioning=Hash([ws_order_number@1], 3), input_partitions=3 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - └────────────────────────────────────────────────── - ┌───── Stage 9 ── tasks=4, partitions=3 - │ RepartitionExec: partitioning=Hash([ws_order_number@1], 3), input_partitions=3 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + ┌───── Stage 14 ── tasks=2, partitions=3 + │ AggregateExec: mode=Partial, gby=[], aggr=[count(alias1), sum(alias2), sum(alias3)] + │ AggregateExec: mode=FinalPartitioned, gby=[alias1@0 as alias1], aggr=[sum(ws1.ws_ext_ship_cost) as alias2, sum(ws1.ws_net_profit) as alias3] + │ [Stage 13] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── + ┌───── Stage 13 ── tasks=4, partitions=6 + │ RepartitionExec: partitioning=Hash([alias1@0], 6), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[ws_order_number@0 as alias1], aggr=[sum(ws1.ws_ext_ship_cost) as alias2, sum(ws1.ws_net_profit) as alias3] + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(ws_order_number@0, wr_order_number@0)] + │ [Stage 8] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 12] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 8 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(ws_order_number@0, ws_order_number@0)] + │ [Stage 4] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 7] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(web_site_sk@0, ws_web_site_sk@0)], projection=[ws_order_number@2, ws_ext_ship_cost@3, ws_net_profit@4] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ca_address_sk@0, ws_ship_addr_sk@0)], projection=[ws_web_site_sk@2, ws_order_number@3, ws_ext_ship_cost@4, ws_net_profit@5] + │ CoalescePartitionsExec + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(d_date_sk@0, ws_ship_date_sk@0)], projection=[ws_ship_addr_sk@2, ws_web_site_sk@3, ws_order_number@4, ws_ext_ship_cost@5, ws_net_profit@6] + │ CoalescePartitionsExec + │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_ship_date_sk, ws_ship_addr_sk, ws_web_site_sk, ws_order_number, ws_ext_ship_cost, ws_net_profit], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: web_company_name@1 = pri, projection=[web_site_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-1.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-2.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_site/part-3.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_site/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_site/part-3.parquet:..]]}, projection=[web_site_sk, web_company_name], file_type=parquet, predicate=web_company_name@14 = pri, pruning_predicate=web_company_name_null_count@2 != row_count@3 AND web_company_name_min@0 <= pri AND pri <= web_company_name_max@1, required_guarantees=[web_company_name in (pri)] + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: ca_state@1 = IL, projection=[ca_address_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/customer_address/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/customer_address/part-3.parquet:..]]}, projection=[ca_address_sk, ca_state], file_type=parquet, predicate=ca_state@8 = IL, pruning_predicate=ca_state_null_count@2 != row_count@3 AND ca_state_min@0 <= IL AND IL <= ca_state_max@1, required_guarantees=[ca_state in (IL)] + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: d_date@1 >= 1999-02-01 AND d_date@1 <= 1999-04-02, projection=[d_date_sk@0] + │ RepartitionExec: partitioning=RoundRobinBatch(3), input_partitions=2 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/date_dim/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/date_dim/part-3.parquet:..]]}, projection=[d_date_sk, d_date], file_type=parquet, predicate=d_date@2 >= 1999-02-01 AND d_date@2 <= 1999-04-02, pruning_predicate=d_date_null_count@1 != row_count@2 AND d_date_max@0 >= 1999-02-01 AND d_date_null_count@1 != row_count@2 AND d_date_min@3 <= 1999-04-02, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 7 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@0], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=Inner, on=[(ws_order_number@1, ws_order_number@1)], filter=ws_warehouse_sk@1 != ws_warehouse_sk@0, projection=[ws_order_number@1] + │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@1], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@1], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 12 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([wr_order_number@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(wr_order_number@0, ws_order_number@0)], projection=[wr_order_number@0] + │ CoalescePartitionsExec + │ [Stage 9] => NetworkBroadcastExec: partitions_per_consumer=2, stage_partitions=8, input_tasks=4 + │ HashJoinExec: mode=Partitioned, join_type=Inner, on=[(ws_order_number@1, ws_order_number@1)], filter=ws_warehouse_sk@1 != ws_warehouse_sk@0, projection=[ws_order_number@1] + │ [Stage 10] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 11] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 9 ── tasks=4, partitions=32 + │ BroadcastExec: input_partitions=2, consumer_tasks=4, output_partitions=8 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={2 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_returns/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_returns/part-3.parquet:..]]}, projection=[wr_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 10 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@1], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 11 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ws_order_number@1], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpcds/plans_sf1_partitions4/web_sales/part-0.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-1.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:.., /testdata/tpcds/plans_sf1_partitions4/web_sales/part-2.parquet:..], [/testdata/tpcds/plans_sf1_partitions4/web_sales/part-3.parquet:..]]}, projection=[ws_warehouse_sk, ws_order_number], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── "); Ok(()) } diff --git a/tests/tpch_plans_test.rs b/tests/tpch_plans_test.rs index 016e21ea..fd534a3a 100644 --- a/tests/tpch_plans_test.rs +++ b/tests/tpch_plans_test.rs @@ -222,29 +222,42 @@ mod tests { #[tokio::test] async fn test_tpch_4() -> Result<(), Box> { let plan = test_tpch_query("q4").await?; - assert_snapshot!(plan, @r" + assert_snapshot!(plan, @" ┌───── DistributedExec │ SortPreservingMergeExec: [o_orderpriority@0 ASC NULLS LAST] - │ SortExec: expr=[o_orderpriority@0 ASC NULLS LAST], preserve_partitioning=[true] - │ ProjectionExec: expr=[o_orderpriority@0 as o_orderpriority, count(Int64(1))@1 as order_count] - │ AggregateExec: mode=FinalPartitioned, gby=[o_orderpriority@0 as o_orderpriority], aggr=[count(Int64(1))] - │ RepartitionExec: partitioning=Hash([o_orderpriority@0], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[o_orderpriority@0 as o_orderpriority], aggr=[count(Int64(1))] - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(o_orderkey@0, l_orderkey@0)], projection=[o_orderpriority@1] - │ CoalescePartitionsExec - │ [Stage 1] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ FilterExec: l_receiptdate@2 > l_commitdate@1, projection=[l_orderkey@0] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., ...], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., ...], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., ...]]}, projection=[l_orderkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + │ [Stage 4] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=12 - │ FilterExec: o_orderdate@1 >= 1993-07-01 AND o_orderdate@1 < 1993-10-01, projection=[o_orderkey@0, o_orderpriority@2] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/1.parquet:.., /testdata/tpch/plan_sf0.02/orders/10.parquet:..], [/testdata/tpch/plan_sf0.02/orders/14.parquet:.., /testdata/tpch/plan_sf0.02/orders/15.parquet:..], [/testdata/tpch/plan_sf0.02/orders/4.parquet:.., /testdata/tpch/plan_sf0.02/orders/5.parquet:..]]}, projection=[o_orderkey, o_orderdate, o_orderpriority], file_type=parquet, predicate=o_orderdate@4 >= 1993-07-01 AND o_orderdate@4 < 1993-10-01, pruning_predicate=o_orderdate_null_count@1 != row_count@2 AND o_orderdate_max@0 >= 1993-07-01 AND o_orderdate_null_count@1 != row_count@2 AND o_orderdate_min@3 < 1993-10-01, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/10.parquet:.., /testdata/tpch/plan_sf0.02/orders/11.parquet:..], [/testdata/tpch/plan_sf0.02/orders/15.parquet:.., /testdata/tpch/plan_sf0.02/orders/16.parquet:.., /testdata/tpch/plan_sf0.02/orders/2.parquet:..], [/testdata/tpch/plan_sf0.02/orders/5.parquet:.., /testdata/tpch/plan_sf0.02/orders/6.parquet:.., /testdata/tpch/plan_sf0.02/orders/7.parquet:..]]}, projection=[o_orderkey, o_orderdate, o_orderpriority], file_type=parquet, predicate=o_orderdate@4 >= 1993-07-01 AND o_orderdate@4 < 1993-10-01, pruning_predicate=o_orderdate_null_count@1 != row_count@2 AND o_orderdate_max@0 >= 1993-07-01 AND o_orderdate_null_count@1 != row_count@2 AND o_orderdate_min@3 < 1993-10-01, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/11.parquet:.., /testdata/tpch/plan_sf0.02/orders/12.parquet:.., /testdata/tpch/plan_sf0.02/orders/13.parquet:..], [/testdata/tpch/plan_sf0.02/orders/2.parquet:.., /testdata/tpch/plan_sf0.02/orders/3.parquet:..], [/testdata/tpch/plan_sf0.02/orders/7.parquet:.., /testdata/tpch/plan_sf0.02/orders/8.parquet:..]]}, projection=[o_orderkey, o_orderdate, o_orderpriority], file_type=parquet, predicate=o_orderdate@4 >= 1993-07-01 AND o_orderdate@4 < 1993-10-01, pruning_predicate=o_orderdate_null_count@1 != row_count@2 AND o_orderdate_max@0 >= 1993-07-01 AND o_orderdate_null_count@1 != row_count@2 AND o_orderdate_min@3 < 1993-10-01, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/13.parquet:.., /testdata/tpch/plan_sf0.02/orders/14.parquet:..], [/testdata/tpch/plan_sf0.02/orders/3.parquet:.., /testdata/tpch/plan_sf0.02/orders/4.parquet:..], [/testdata/tpch/plan_sf0.02/orders/8.parquet:.., /testdata/tpch/plan_sf0.02/orders/9.parquet:..]]}, projection=[o_orderkey, o_orderdate, o_orderpriority], file_type=parquet, predicate=o_orderdate@4 >= 1993-07-01 AND o_orderdate@4 < 1993-10-01, pruning_predicate=o_orderdate_null_count@1 != row_count@2 AND o_orderdate_max@0 >= 1993-07-01 AND o_orderdate_null_count@1 != row_count@2 AND o_orderdate_min@3 < 1993-10-01, required_guarantees=[] + ┌───── Stage 4 ── tasks=2, partitions=3 + │ SortExec: expr=[o_orderpriority@0 ASC NULLS LAST], preserve_partitioning=[true] + │ ProjectionExec: expr=[o_orderpriority@0 as o_orderpriority, count(Int64(1))@1 as order_count] + │ AggregateExec: mode=FinalPartitioned, gby=[o_orderpriority@0 as o_orderpriority], aggr=[count(Int64(1))] + │ [Stage 3] => NetworkShuffleExec: output_partitions=3, input_tasks=3 └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=3, partitions=6 + │ RepartitionExec: partitioning=Hash([o_orderpriority@0], 6), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[o_orderpriority@0 as o_orderpriority], aggr=[count(Int64(1))] + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(o_orderkey@0, l_orderkey@0)], projection=[o_orderpriority@1] + │ [Stage 1] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 2] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=9 + │ RepartitionExec: partitioning=Hash([o_orderkey@0], 9), input_partitions=3 + │ FilterExec: o_orderdate@1 >= 1993-07-01 AND o_orderdate@1 < 1993-10-01, projection=[o_orderkey@0, o_orderpriority@2] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/1.parquet:.., /testdata/tpch/plan_sf0.02/orders/10.parquet:..], [/testdata/tpch/plan_sf0.02/orders/14.parquet:.., /testdata/tpch/plan_sf0.02/orders/15.parquet:..], [/testdata/tpch/plan_sf0.02/orders/4.parquet:.., /testdata/tpch/plan_sf0.02/orders/5.parquet:..]]}, projection=[o_orderkey, o_orderdate, o_orderpriority], file_type=parquet, predicate=o_orderdate@4 >= 1993-07-01 AND o_orderdate@4 < 1993-10-01, pruning_predicate=o_orderdate_null_count@1 != row_count@2 AND o_orderdate_max@0 >= 1993-07-01 AND o_orderdate_null_count@1 != row_count@2 AND o_orderdate_min@3 < 1993-10-01, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/10.parquet:.., /testdata/tpch/plan_sf0.02/orders/11.parquet:..], [/testdata/tpch/plan_sf0.02/orders/15.parquet:.., /testdata/tpch/plan_sf0.02/orders/16.parquet:.., /testdata/tpch/plan_sf0.02/orders/2.parquet:..], [/testdata/tpch/plan_sf0.02/orders/5.parquet:.., /testdata/tpch/plan_sf0.02/orders/6.parquet:.., /testdata/tpch/plan_sf0.02/orders/7.parquet:..]]}, projection=[o_orderkey, o_orderdate, o_orderpriority], file_type=parquet, predicate=o_orderdate@4 >= 1993-07-01 AND o_orderdate@4 < 1993-10-01, pruning_predicate=o_orderdate_null_count@1 != row_count@2 AND o_orderdate_max@0 >= 1993-07-01 AND o_orderdate_null_count@1 != row_count@2 AND o_orderdate_min@3 < 1993-10-01, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/11.parquet:.., /testdata/tpch/plan_sf0.02/orders/12.parquet:.., /testdata/tpch/plan_sf0.02/orders/13.parquet:..], [/testdata/tpch/plan_sf0.02/orders/2.parquet:.., /testdata/tpch/plan_sf0.02/orders/3.parquet:..], [/testdata/tpch/plan_sf0.02/orders/7.parquet:.., /testdata/tpch/plan_sf0.02/orders/8.parquet:..]]}, projection=[o_orderkey, o_orderdate, o_orderpriority], file_type=parquet, predicate=o_orderdate@4 >= 1993-07-01 AND o_orderdate@4 < 1993-10-01, pruning_predicate=o_orderdate_null_count@1 != row_count@2 AND o_orderdate_max@0 >= 1993-07-01 AND o_orderdate_null_count@1 != row_count@2 AND o_orderdate_min@3 < 1993-10-01, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/13.parquet:.., /testdata/tpch/plan_sf0.02/orders/14.parquet:..], [/testdata/tpch/plan_sf0.02/orders/3.parquet:.., /testdata/tpch/plan_sf0.02/orders/4.parquet:..], [/testdata/tpch/plan_sf0.02/orders/8.parquet:.., /testdata/tpch/plan_sf0.02/orders/9.parquet:..]]}, projection=[o_orderkey, o_orderdate, o_orderpriority], file_type=parquet, predicate=o_orderdate@4 >= 1993-07-01 AND o_orderdate@4 < 1993-10-01, pruning_predicate=o_orderdate_null_count@1 != row_count@2 AND o_orderdate_max@0 >= 1993-07-01 AND o_orderdate_null_count@1 != row_count@2 AND o_orderdate_min@3 < 1993-10-01, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=9 + │ RepartitionExec: partitioning=Hash([l_orderkey@0], 9), input_partitions=3 + │ FilterExec: l_receiptdate@2 > l_commitdate@1, projection=[l_orderkey@0] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:..]]}, projection=[l_orderkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:..]]}, projection=[l_orderkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:..]]}, projection=[l_orderkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/14.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/4.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/9.parquet:..]]}, projection=[l_orderkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── "); Ok(()) } @@ -830,41 +843,48 @@ mod tests { #[tokio::test] async fn test_tpch_13() -> Result<(), Box> { let plan = test_tpch_query("q13").await?; - assert_snapshot!(plan, @r" + assert_snapshot!(plan, @" ┌───── DistributedExec │ SortPreservingMergeExec: [custdist@1 DESC, c_count@0 DESC] - │ [Stage 3] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 + │ [Stage 5] => NetworkCoalesceExec: output_partitions=6, input_tasks=2 └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=2, partitions=3 + ┌───── Stage 5 ── tasks=2, partitions=3 │ SortExec: expr=[custdist@1 DESC, c_count@0 DESC], preserve_partitioning=[true] │ ProjectionExec: expr=[c_count@0 as c_count, count(Int64(1))@1 as custdist] │ AggregateExec: mode=FinalPartitioned, gby=[c_count@0 as c_count], aggr=[count(Int64(1))] - │ [Stage 2] => NetworkShuffleExec: output_partitions=3, input_tasks=3 + │ [Stage 4] => NetworkShuffleExec: output_partitions=3, input_tasks=3 └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=3, partitions=6 + ┌───── Stage 4 ── tasks=3, partitions=6 │ RepartitionExec: partitioning=Hash([c_count@0], 6), input_partitions=3 │ AggregateExec: mode=Partial, gby=[c_count@0 as c_count], aggr=[count(Int64(1))] │ ProjectionExec: expr=[count(orders.o_orderkey)@1 as c_count] │ AggregateExec: mode=FinalPartitioned, gby=[c_custkey@0 as c_custkey], aggr=[count(orders.o_orderkey)] - │ [Stage 1] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 3] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=9 + ┌───── Stage 3 ── tasks=4, partitions=9 │ RepartitionExec: partitioning=Hash([c_custkey@0], 9), input_partitions=3 │ AggregateExec: mode=Partial, gby=[c_custkey@0 as c_custkey], aggr=[count(orders.o_orderkey)] - │ HashJoinExec: mode=CollectLeft, join_type=Left, on=[(c_custkey@0, o_custkey@1)], projection=[c_custkey@0, o_orderkey@1] - │ CoalescePartitionsExec - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/1.parquet:.., /testdata/tpch/plan_sf0.02/customer/10.parquet:..], [/testdata/tpch/plan_sf0.02/customer/14.parquet:.., /testdata/tpch/plan_sf0.02/customer/15.parquet:..], [/testdata/tpch/plan_sf0.02/customer/4.parquet:.., /testdata/tpch/plan_sf0.02/customer/5.parquet:.., /testdata/tpch/plan_sf0.02/customer/6.parquet:..]]}, projection=[c_custkey], file_type=parquet - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/10.parquet:.., /testdata/tpch/plan_sf0.02/customer/11.parquet:..], [/testdata/tpch/plan_sf0.02/customer/15.parquet:.., /testdata/tpch/plan_sf0.02/customer/16.parquet:..], [/testdata/tpch/plan_sf0.02/customer/6.parquet:.., /testdata/tpch/plan_sf0.02/customer/7.parquet:..]]}, projection=[c_custkey], file_type=parquet - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/11.parquet:.., /testdata/tpch/plan_sf0.02/customer/12.parquet:.., /testdata/tpch/plan_sf0.02/customer/13.parquet:..], [/testdata/tpch/plan_sf0.02/customer/16.parquet:.., /testdata/tpch/plan_sf0.02/customer/2.parquet:.., /testdata/tpch/plan_sf0.02/customer/3.parquet:..], [/testdata/tpch/plan_sf0.02/customer/7.parquet:.., /testdata/tpch/plan_sf0.02/customer/8.parquet:..]]}, projection=[c_custkey], file_type=parquet - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/13.parquet:.., /testdata/tpch/plan_sf0.02/customer/14.parquet:..], [/testdata/tpch/plan_sf0.02/customer/3.parquet:.., /testdata/tpch/plan_sf0.02/customer/4.parquet:..], [/testdata/tpch/plan_sf0.02/customer/8.parquet:.., /testdata/tpch/plan_sf0.02/customer/9.parquet:..]]}, projection=[c_custkey], file_type=parquet - │ FilterExec: o_comment@2 NOT LIKE %special%requests%, projection=[o_orderkey@0, o_custkey@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/1.parquet:.., /testdata/tpch/plan_sf0.02/orders/10.parquet:..], [/testdata/tpch/plan_sf0.02/orders/14.parquet:.., /testdata/tpch/plan_sf0.02/orders/15.parquet:..], [/testdata/tpch/plan_sf0.02/orders/4.parquet:.., /testdata/tpch/plan_sf0.02/orders/5.parquet:..]]}, projection=[o_orderkey, o_custkey, o_comment], file_type=parquet, predicate=o_comment@8 NOT LIKE %special%requests% AND DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/10.parquet:.., /testdata/tpch/plan_sf0.02/orders/11.parquet:..], [/testdata/tpch/plan_sf0.02/orders/15.parquet:.., /testdata/tpch/plan_sf0.02/orders/16.parquet:.., /testdata/tpch/plan_sf0.02/orders/2.parquet:..], [/testdata/tpch/plan_sf0.02/orders/5.parquet:.., /testdata/tpch/plan_sf0.02/orders/6.parquet:.., /testdata/tpch/plan_sf0.02/orders/7.parquet:..]]}, projection=[o_orderkey, o_custkey, o_comment], file_type=parquet, predicate=o_comment@8 NOT LIKE %special%requests% AND DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/11.parquet:.., /testdata/tpch/plan_sf0.02/orders/12.parquet:.., /testdata/tpch/plan_sf0.02/orders/13.parquet:..], [/testdata/tpch/plan_sf0.02/orders/2.parquet:.., /testdata/tpch/plan_sf0.02/orders/3.parquet:..], [/testdata/tpch/plan_sf0.02/orders/7.parquet:.., /testdata/tpch/plan_sf0.02/orders/8.parquet:..]]}, projection=[o_orderkey, o_custkey, o_comment], file_type=parquet, predicate=o_comment@8 NOT LIKE %special%requests% AND DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/13.parquet:.., /testdata/tpch/plan_sf0.02/orders/14.parquet:..], [/testdata/tpch/plan_sf0.02/orders/3.parquet:.., /testdata/tpch/plan_sf0.02/orders/4.parquet:..], [/testdata/tpch/plan_sf0.02/orders/8.parquet:.., /testdata/tpch/plan_sf0.02/orders/9.parquet:..]]}, projection=[o_orderkey, o_custkey, o_comment], file_type=parquet, predicate=o_comment@8 NOT LIKE %special%requests% AND DynamicFilter [ empty ] + │ HashJoinExec: mode=Partitioned, join_type=Left, on=[(c_custkey@0, o_custkey@1)], projection=[c_custkey@0, o_orderkey@1] + │ [Stage 1] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 2] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_custkey@0], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/1.parquet:.., /testdata/tpch/plan_sf0.02/customer/10.parquet:..], [/testdata/tpch/plan_sf0.02/customer/14.parquet:.., /testdata/tpch/plan_sf0.02/customer/15.parquet:..], [/testdata/tpch/plan_sf0.02/customer/4.parquet:.., /testdata/tpch/plan_sf0.02/customer/5.parquet:.., /testdata/tpch/plan_sf0.02/customer/6.parquet:..]]}, projection=[c_custkey], file_type=parquet + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/10.parquet:.., /testdata/tpch/plan_sf0.02/customer/11.parquet:..], [/testdata/tpch/plan_sf0.02/customer/15.parquet:.., /testdata/tpch/plan_sf0.02/customer/16.parquet:..], [/testdata/tpch/plan_sf0.02/customer/6.parquet:.., /testdata/tpch/plan_sf0.02/customer/7.parquet:..]]}, projection=[c_custkey], file_type=parquet + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/11.parquet:.., /testdata/tpch/plan_sf0.02/customer/12.parquet:.., /testdata/tpch/plan_sf0.02/customer/13.parquet:..], [/testdata/tpch/plan_sf0.02/customer/16.parquet:.., /testdata/tpch/plan_sf0.02/customer/2.parquet:.., /testdata/tpch/plan_sf0.02/customer/3.parquet:..], [/testdata/tpch/plan_sf0.02/customer/7.parquet:.., /testdata/tpch/plan_sf0.02/customer/8.parquet:..]]}, projection=[c_custkey], file_type=parquet + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/13.parquet:.., /testdata/tpch/plan_sf0.02/customer/14.parquet:..], [/testdata/tpch/plan_sf0.02/customer/3.parquet:.., /testdata/tpch/plan_sf0.02/customer/4.parquet:..], [/testdata/tpch/plan_sf0.02/customer/8.parquet:.., /testdata/tpch/plan_sf0.02/customer/9.parquet:..]]}, projection=[c_custkey], file_type=parquet + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([o_custkey@1], 12), input_partitions=3 + │ FilterExec: o_comment@2 NOT LIKE %special%requests%, projection=[o_orderkey@0, o_custkey@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/1.parquet:.., /testdata/tpch/plan_sf0.02/orders/10.parquet:..], [/testdata/tpch/plan_sf0.02/orders/14.parquet:.., /testdata/tpch/plan_sf0.02/orders/15.parquet:..], [/testdata/tpch/plan_sf0.02/orders/4.parquet:.., /testdata/tpch/plan_sf0.02/orders/5.parquet:..]]}, projection=[o_orderkey, o_custkey, o_comment], file_type=parquet, predicate=o_comment@8 NOT LIKE %special%requests% AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/10.parquet:.., /testdata/tpch/plan_sf0.02/orders/11.parquet:..], [/testdata/tpch/plan_sf0.02/orders/15.parquet:.., /testdata/tpch/plan_sf0.02/orders/16.parquet:.., /testdata/tpch/plan_sf0.02/orders/2.parquet:..], [/testdata/tpch/plan_sf0.02/orders/5.parquet:.., /testdata/tpch/plan_sf0.02/orders/6.parquet:.., /testdata/tpch/plan_sf0.02/orders/7.parquet:..]]}, projection=[o_orderkey, o_custkey, o_comment], file_type=parquet, predicate=o_comment@8 NOT LIKE %special%requests% AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/11.parquet:.., /testdata/tpch/plan_sf0.02/orders/12.parquet:.., /testdata/tpch/plan_sf0.02/orders/13.parquet:..], [/testdata/tpch/plan_sf0.02/orders/2.parquet:.., /testdata/tpch/plan_sf0.02/orders/3.parquet:..], [/testdata/tpch/plan_sf0.02/orders/7.parquet:.., /testdata/tpch/plan_sf0.02/orders/8.parquet:..]]}, projection=[o_orderkey, o_custkey, o_comment], file_type=parquet, predicate=o_comment@8 NOT LIKE %special%requests% AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/13.parquet:.., /testdata/tpch/plan_sf0.02/orders/14.parquet:..], [/testdata/tpch/plan_sf0.02/orders/3.parquet:.., /testdata/tpch/plan_sf0.02/orders/4.parquet:..], [/testdata/tpch/plan_sf0.02/orders/8.parquet:.., /testdata/tpch/plan_sf0.02/orders/9.parquet:..]]}, projection=[o_orderkey, o_custkey, o_comment], file_type=parquet, predicate=o_comment@8 NOT LIKE %special%requests% AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── "); Ok(()) } @@ -1181,69 +1201,76 @@ mod tests { #[tokio::test] async fn test_tpch_20() -> Result<(), Box> { let plan = test_tpch_query("q20").await?; - assert_snapshot!(plan, @r" + assert_snapshot!(plan, @" ┌───── DistributedExec │ SortPreservingMergeExec: [s_name@0 ASC NULLS LAST] - │ SortExec: expr=[s_name@0 ASC NULLS LAST], preserve_partitioning=[true] - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(s_suppkey@0, ps_suppkey@0)], projection=[s_name@1, s_address@2] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ps_partkey@0, l_partkey@1), (ps_suppkey@1, l_suppkey@2)], filter=CAST(ps_availqty@0 AS Float64) > Float64(0.5) * sum(lineitem.l_quantity)@1, projection=[ps_suppkey@1] - │ CoalescePartitionsExec - │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=3, input_tasks=4 - │ ProjectionExec: expr=[0.5 * CAST(sum(lineitem.l_quantity)@2 AS Float64) as Float64(0.5) * sum(lineitem.l_quantity), l_partkey@0 as l_partkey, l_suppkey@1 as l_suppkey] - │ AggregateExec: mode=FinalPartitioned, gby=[l_partkey@0 as l_partkey, l_suppkey@1 as l_suppkey], aggr=[sum(lineitem.l_quantity)] - │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 7] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(n_nationkey@0, s_nationkey@3)], projection=[s_suppkey@1, s_name@2, s_address@3] - │ CoalescePartitionsExec - │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/1.parquet:.., /testdata/tpch/plan_sf0.02/supplier/10.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/14.parquet:.., /testdata/tpch/plan_sf0.02/supplier/15.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/4.parquet:.., /testdata/tpch/plan_sf0.02/supplier/5.parquet:..]]}, projection=[s_suppkey, s_name, s_address, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/10.parquet:.., /testdata/tpch/plan_sf0.02/supplier/11.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/15.parquet:.., /testdata/tpch/plan_sf0.02/supplier/16.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/5.parquet:.., /testdata/tpch/plan_sf0.02/supplier/6.parquet:.., /testdata/tpch/plan_sf0.02/supplier/7.parquet:..]]}, projection=[s_suppkey, s_name, s_address, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/11.parquet:.., /testdata/tpch/plan_sf0.02/supplier/12.parquet:.., /testdata/tpch/plan_sf0.02/supplier/13.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/16.parquet:.., /testdata/tpch/plan_sf0.02/supplier/2.parquet:.., /testdata/tpch/plan_sf0.02/supplier/3.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/7.parquet:.., /testdata/tpch/plan_sf0.02/supplier/8.parquet:..]]}, projection=[s_suppkey, s_name, s_address, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/13.parquet:.., /testdata/tpch/plan_sf0.02/supplier/14.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/3.parquet:.., /testdata/tpch/plan_sf0.02/supplier/4.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/8.parquet:.., /testdata/tpch/plan_sf0.02/supplier/9.parquet:..]]}, projection=[s_suppkey, s_name, s_address, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] + ┌───── Stage 7 ── tasks=4, partitions=3 + │ SortExec: expr=[s_name@0 ASC NULLS LAST], preserve_partitioning=[true] + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(s_suppkey@0, ps_suppkey@0)], projection=[s_name@1, s_address@2] + │ [Stage 2] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: n_name@1 = CANADA, projection=[n_nationkey@0] + ┌───── Stage 2 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([s_suppkey@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(n_nationkey@0, s_nationkey@3)], projection=[s_suppkey@1, s_name@2, s_address@3] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/1.parquet:.., /testdata/tpch/plan_sf0.02/nation/10.parquet:..], [/testdata/tpch/plan_sf0.02/nation/14.parquet:.., /testdata/tpch/plan_sf0.02/nation/15.parquet:..], [/testdata/tpch/plan_sf0.02/nation/4.parquet:.., /testdata/tpch/plan_sf0.02/nation/5.parquet:.., /testdata/tpch/plan_sf0.02/nation/6.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = CANADA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= CANADA AND CANADA <= n_name_max@1, required_guarantees=[n_name in (CANADA)] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/10.parquet:.., /testdata/tpch/plan_sf0.02/nation/11.parquet:..], [/testdata/tpch/plan_sf0.02/nation/15.parquet:.., /testdata/tpch/plan_sf0.02/nation/16.parquet:.., /testdata/tpch/plan_sf0.02/nation/2.parquet:..], [/testdata/tpch/plan_sf0.02/nation/6.parquet:.., /testdata/tpch/plan_sf0.02/nation/7.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = CANADA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= CANADA AND CANADA <= n_name_max@1, required_guarantees=[n_name in (CANADA)] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/11.parquet:.., /testdata/tpch/plan_sf0.02/nation/12.parquet:.., /testdata/tpch/plan_sf0.02/nation/13.parquet:..], [/testdata/tpch/plan_sf0.02/nation/2.parquet:.., /testdata/tpch/plan_sf0.02/nation/3.parquet:..], [/testdata/tpch/plan_sf0.02/nation/7.parquet:.., /testdata/tpch/plan_sf0.02/nation/8.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = CANADA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= CANADA AND CANADA <= n_name_max@1, required_guarantees=[n_name in (CANADA)] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/13.parquet:.., /testdata/tpch/plan_sf0.02/nation/14.parquet:..], [/testdata/tpch/plan_sf0.02/nation/3.parquet:.., /testdata/tpch/plan_sf0.02/nation/4.parquet:..], [/testdata/tpch/plan_sf0.02/nation/8.parquet:.., /testdata/tpch/plan_sf0.02/nation/9.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = CANADA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= CANADA AND CANADA <= n_name_max@1, required_guarantees=[n_name in (CANADA)] + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/1.parquet:.., /testdata/tpch/plan_sf0.02/supplier/10.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/14.parquet:.., /testdata/tpch/plan_sf0.02/supplier/15.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/4.parquet:.., /testdata/tpch/plan_sf0.02/supplier/5.parquet:..]]}, projection=[s_suppkey, s_name, s_address, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/10.parquet:.., /testdata/tpch/plan_sf0.02/supplier/11.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/15.parquet:.., /testdata/tpch/plan_sf0.02/supplier/16.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/5.parquet:.., /testdata/tpch/plan_sf0.02/supplier/6.parquet:.., /testdata/tpch/plan_sf0.02/supplier/7.parquet:..]]}, projection=[s_suppkey, s_name, s_address, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/11.parquet:.., /testdata/tpch/plan_sf0.02/supplier/12.parquet:.., /testdata/tpch/plan_sf0.02/supplier/13.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/16.parquet:.., /testdata/tpch/plan_sf0.02/supplier/2.parquet:.., /testdata/tpch/plan_sf0.02/supplier/3.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/7.parquet:.., /testdata/tpch/plan_sf0.02/supplier/8.parquet:..]]}, projection=[s_suppkey, s_name, s_address, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/13.parquet:.., /testdata/tpch/plan_sf0.02/supplier/14.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/3.parquet:.., /testdata/tpch/plan_sf0.02/supplier/4.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/8.parquet:.., /testdata/tpch/plan_sf0.02/supplier/9.parquet:..]]}, projection=[s_suppkey, s_name, s_address, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ BroadcastExec: input_partitions=3, consumer_tasks=1, output_partitions=3 - │ HashJoinExec: mode=CollectLeft, join_type=RightSemi, on=[(p_partkey@0, ps_partkey@0)] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/partsupp/1.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/10.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/14.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/15.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/4.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/5.parquet:..]]}, projection=[ps_partkey, ps_suppkey, ps_availqty], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/partsupp/10.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/11.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/15.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/16.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/5.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/6.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/7.parquet:..]]}, projection=[ps_partkey, ps_suppkey, ps_availqty], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/partsupp/11.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/12.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/16.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/2.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/3.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/7.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/8.parquet:..]]}, projection=[ps_partkey, ps_suppkey, ps_availqty], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/partsupp/12.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/13.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/14.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/3.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/4.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/8.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/9.parquet:..]]}, projection=[ps_partkey, ps_suppkey, ps_availqty], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] - └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: p_name@1 LIKE forest%, projection=[p_partkey@0] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/part/1.parquet:.., /testdata/tpch/plan_sf0.02/part/10.parquet:..], [/testdata/tpch/plan_sf0.02/part/14.parquet:.., /testdata/tpch/plan_sf0.02/part/15.parquet:..], [/testdata/tpch/plan_sf0.02/part/4.parquet:.., /testdata/tpch/plan_sf0.02/part/5.parquet:..]]}, projection=[p_partkey, p_name], file_type=parquet, predicate=p_name@1 LIKE forest%, pruning_predicate=p_name_null_count@2 != row_count@3 AND p_name_min@0 <= foresu AND forest <= p_name_max@1, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/part/10.parquet:.., /testdata/tpch/plan_sf0.02/part/11.parquet:..], [/testdata/tpch/plan_sf0.02/part/15.parquet:.., /testdata/tpch/plan_sf0.02/part/16.parquet:.., /testdata/tpch/plan_sf0.02/part/2.parquet:..], [/testdata/tpch/plan_sf0.02/part/5.parquet:.., /testdata/tpch/plan_sf0.02/part/6.parquet:.., /testdata/tpch/plan_sf0.02/part/7.parquet:..]]}, projection=[p_partkey, p_name], file_type=parquet, predicate=p_name@1 LIKE forest%, pruning_predicate=p_name_null_count@2 != row_count@3 AND p_name_min@0 <= foresu AND forest <= p_name_max@1, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/part/11.parquet:.., /testdata/tpch/plan_sf0.02/part/12.parquet:..], [/testdata/tpch/plan_sf0.02/part/2.parquet:.., /testdata/tpch/plan_sf0.02/part/3.parquet:..], [/testdata/tpch/plan_sf0.02/part/7.parquet:.., /testdata/tpch/plan_sf0.02/part/8.parquet:..]]}, projection=[p_partkey, p_name], file_type=parquet, predicate=p_name@1 LIKE forest%, pruning_predicate=p_name_null_count@2 != row_count@3 AND p_name_min@0 <= foresu AND forest <= p_name_max@1, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/part/12.parquet:.., /testdata/tpch/plan_sf0.02/part/13.parquet:.., /testdata/tpch/plan_sf0.02/part/14.parquet:..], [/testdata/tpch/plan_sf0.02/part/3.parquet:.., /testdata/tpch/plan_sf0.02/part/4.parquet:..], [/testdata/tpch/plan_sf0.02/part/8.parquet:.., /testdata/tpch/plan_sf0.02/part/9.parquet:..]]}, projection=[p_partkey, p_name], file_type=parquet, predicate=p_name@1 LIKE forest%, pruning_predicate=p_name_null_count@2 != row_count@3 AND p_name_min@0 <= foresu AND forest <= p_name_max@1, required_guarantees=[] + ┌───── Stage 1 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: n_name@1 = CANADA, projection=[n_nationkey@0] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/1.parquet:.., /testdata/tpch/plan_sf0.02/nation/10.parquet:..], [/testdata/tpch/plan_sf0.02/nation/14.parquet:.., /testdata/tpch/plan_sf0.02/nation/15.parquet:..], [/testdata/tpch/plan_sf0.02/nation/4.parquet:.., /testdata/tpch/plan_sf0.02/nation/5.parquet:.., /testdata/tpch/plan_sf0.02/nation/6.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = CANADA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= CANADA AND CANADA <= n_name_max@1, required_guarantees=[n_name in (CANADA)] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/10.parquet:.., /testdata/tpch/plan_sf0.02/nation/11.parquet:..], [/testdata/tpch/plan_sf0.02/nation/15.parquet:.., /testdata/tpch/plan_sf0.02/nation/16.parquet:.., /testdata/tpch/plan_sf0.02/nation/2.parquet:..], [/testdata/tpch/plan_sf0.02/nation/6.parquet:.., /testdata/tpch/plan_sf0.02/nation/7.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = CANADA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= CANADA AND CANADA <= n_name_max@1, required_guarantees=[n_name in (CANADA)] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/11.parquet:.., /testdata/tpch/plan_sf0.02/nation/12.parquet:.., /testdata/tpch/plan_sf0.02/nation/13.parquet:..], [/testdata/tpch/plan_sf0.02/nation/2.parquet:.., /testdata/tpch/plan_sf0.02/nation/3.parquet:..], [/testdata/tpch/plan_sf0.02/nation/7.parquet:.., /testdata/tpch/plan_sf0.02/nation/8.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = CANADA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= CANADA AND CANADA <= n_name_max@1, required_guarantees=[n_name in (CANADA)] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/13.parquet:.., /testdata/tpch/plan_sf0.02/nation/14.parquet:..], [/testdata/tpch/plan_sf0.02/nation/3.parquet:.., /testdata/tpch/plan_sf0.02/nation/4.parquet:..], [/testdata/tpch/plan_sf0.02/nation/8.parquet:.., /testdata/tpch/plan_sf0.02/nation/9.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = CANADA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= CANADA AND CANADA <= n_name_max@1, required_guarantees=[n_name in (CANADA)] + └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([ps_suppkey@0], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(ps_partkey@0, l_partkey@1), (ps_suppkey@1, l_suppkey@2)], filter=CAST(ps_availqty@0 AS Float64) > Float64(0.5) * sum(lineitem.l_quantity)@1, projection=[ps_suppkey@1] + │ CoalescePartitionsExec + │ [Stage 4] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ ProjectionExec: expr=[0.5 * CAST(sum(lineitem.l_quantity)@2 AS Float64) as Float64(0.5) * sum(lineitem.l_quantity), l_partkey@0 as l_partkey, l_suppkey@1 as l_suppkey] + │ AggregateExec: mode=FinalPartitioned, gby=[l_partkey@0 as l_partkey, l_suppkey@1 as l_suppkey], aggr=[sum(lineitem.l_quantity)] + │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 5 ── tasks=4, partitions=3 - │ RepartitionExec: partitioning=Hash([l_partkey@0, l_suppkey@1], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[l_partkey@0 as l_partkey, l_suppkey@1 as l_suppkey], aggr=[sum(lineitem.l_quantity)] - │ FilterExec: l_shipdate@3 >= 1994-01-01 AND l_shipdate@3 < 1995-01-01, projection=[l_partkey@0, l_suppkey@1, l_quantity@2] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:..]]}, projection=[l_partkey, l_suppkey, l_quantity, l_shipdate], file_type=parquet, predicate=l_shipdate@10 >= 1994-01-01 AND l_shipdate@10 < 1995-01-01 AND DynamicFilter [ empty ], pruning_predicate=l_shipdate_null_count@1 != row_count@2 AND l_shipdate_max@0 >= 1994-01-01 AND l_shipdate_null_count@1 != row_count@2 AND l_shipdate_min@3 < 1995-01-01, required_guarantees=[] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:..]]}, projection=[l_partkey, l_suppkey, l_quantity, l_shipdate], file_type=parquet, predicate=l_shipdate@10 >= 1994-01-01 AND l_shipdate@10 < 1995-01-01 AND DynamicFilter [ empty ], pruning_predicate=l_shipdate_null_count@1 != row_count@2 AND l_shipdate_max@0 >= 1994-01-01 AND l_shipdate_null_count@1 != row_count@2 AND l_shipdate_min@3 < 1995-01-01, required_guarantees=[] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:..]]}, projection=[l_partkey, l_suppkey, l_quantity, l_shipdate], file_type=parquet, predicate=l_shipdate@10 >= 1994-01-01 AND l_shipdate@10 < 1995-01-01 AND DynamicFilter [ empty ], pruning_predicate=l_shipdate_null_count@1 != row_count@2 AND l_shipdate_max@0 >= 1994-01-01 AND l_shipdate_null_count@1 != row_count@2 AND l_shipdate_min@3 < 1995-01-01, required_guarantees=[] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/14.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/4.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/9.parquet:..]]}, projection=[l_partkey, l_suppkey, l_quantity, l_shipdate], file_type=parquet, predicate=l_shipdate@10 >= 1994-01-01 AND l_shipdate@10 < 1995-01-01 AND DynamicFilter [ empty ], pruning_predicate=l_shipdate_null_count@1 != row_count@2 AND l_shipdate_max@0 >= 1994-01-01 AND l_shipdate_null_count@1 != row_count@2 AND l_shipdate_min@3 < 1995-01-01, required_guarantees=[] - └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ HashJoinExec: mode=CollectLeft, join_type=RightSemi, on=[(p_partkey@0, ps_partkey@0)] + │ CoalescePartitionsExec + │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/partsupp/1.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/10.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/14.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/15.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/4.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/5.parquet:..]]}, projection=[ps_partkey, ps_suppkey, ps_availqty], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/partsupp/10.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/11.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/15.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/16.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/5.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/6.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/7.parquet:..]]}, projection=[ps_partkey, ps_suppkey, ps_availqty], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/partsupp/11.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/12.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/16.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/2.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/3.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/7.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/8.parquet:..]]}, projection=[ps_partkey, ps_suppkey, ps_availqty], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/partsupp/12.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/13.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/14.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/3.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/4.parquet:..], [/testdata/tpch/plan_sf0.02/partsupp/8.parquet:.., /testdata/tpch/plan_sf0.02/partsupp/9.parquet:..]]}, projection=[ps_partkey, ps_suppkey, ps_availqty], file_type=parquet, predicate=DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: p_name@1 LIKE forest%, projection=[p_partkey@0] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/part/1.parquet:.., /testdata/tpch/plan_sf0.02/part/10.parquet:..], [/testdata/tpch/plan_sf0.02/part/14.parquet:.., /testdata/tpch/plan_sf0.02/part/15.parquet:..], [/testdata/tpch/plan_sf0.02/part/4.parquet:.., /testdata/tpch/plan_sf0.02/part/5.parquet:..]]}, projection=[p_partkey, p_name], file_type=parquet, predicate=p_name@1 LIKE forest%, pruning_predicate=p_name_null_count@2 != row_count@3 AND p_name_min@0 <= foresu AND forest <= p_name_max@1, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/part/10.parquet:.., /testdata/tpch/plan_sf0.02/part/11.parquet:..], [/testdata/tpch/plan_sf0.02/part/15.parquet:.., /testdata/tpch/plan_sf0.02/part/16.parquet:.., /testdata/tpch/plan_sf0.02/part/2.parquet:..], [/testdata/tpch/plan_sf0.02/part/5.parquet:.., /testdata/tpch/plan_sf0.02/part/6.parquet:.., /testdata/tpch/plan_sf0.02/part/7.parquet:..]]}, projection=[p_partkey, p_name], file_type=parquet, predicate=p_name@1 LIKE forest%, pruning_predicate=p_name_null_count@2 != row_count@3 AND p_name_min@0 <= foresu AND forest <= p_name_max@1, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/part/11.parquet:.., /testdata/tpch/plan_sf0.02/part/12.parquet:..], [/testdata/tpch/plan_sf0.02/part/2.parquet:.., /testdata/tpch/plan_sf0.02/part/3.parquet:..], [/testdata/tpch/plan_sf0.02/part/7.parquet:.., /testdata/tpch/plan_sf0.02/part/8.parquet:..]]}, projection=[p_partkey, p_name], file_type=parquet, predicate=p_name@1 LIKE forest%, pruning_predicate=p_name_null_count@2 != row_count@3 AND p_name_min@0 <= foresu AND forest <= p_name_max@1, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/part/12.parquet:.., /testdata/tpch/plan_sf0.02/part/13.parquet:.., /testdata/tpch/plan_sf0.02/part/14.parquet:..], [/testdata/tpch/plan_sf0.02/part/3.parquet:.., /testdata/tpch/plan_sf0.02/part/4.parquet:..], [/testdata/tpch/plan_sf0.02/part/8.parquet:.., /testdata/tpch/plan_sf0.02/part/9.parquet:..]]}, projection=[p_partkey, p_name], file_type=parquet, predicate=p_name@1 LIKE forest%, pruning_predicate=p_name_null_count@2 != row_count@3 AND p_name_min@0 <= foresu AND forest <= p_name_max@1, required_guarantees=[] + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([l_partkey@0, l_suppkey@1], 12), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[l_partkey@0 as l_partkey, l_suppkey@1 as l_suppkey], aggr=[sum(lineitem.l_quantity)] + │ FilterExec: l_shipdate@3 >= 1994-01-01 AND l_shipdate@3 < 1995-01-01, projection=[l_partkey@0, l_suppkey@1, l_quantity@2] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:..]]}, projection=[l_partkey, l_suppkey, l_quantity, l_shipdate], file_type=parquet, predicate=l_shipdate@10 >= 1994-01-01 AND l_shipdate@10 < 1995-01-01 AND DynamicFilter [ empty ], pruning_predicate=l_shipdate_null_count@1 != row_count@2 AND l_shipdate_max@0 >= 1994-01-01 AND l_shipdate_null_count@1 != row_count@2 AND l_shipdate_min@3 < 1995-01-01, required_guarantees=[] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:..]]}, projection=[l_partkey, l_suppkey, l_quantity, l_shipdate], file_type=parquet, predicate=l_shipdate@10 >= 1994-01-01 AND l_shipdate@10 < 1995-01-01 AND DynamicFilter [ empty ], pruning_predicate=l_shipdate_null_count@1 != row_count@2 AND l_shipdate_max@0 >= 1994-01-01 AND l_shipdate_null_count@1 != row_count@2 AND l_shipdate_min@3 < 1995-01-01, required_guarantees=[] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:..]]}, projection=[l_partkey, l_suppkey, l_quantity, l_shipdate], file_type=parquet, predicate=l_shipdate@10 >= 1994-01-01 AND l_shipdate@10 < 1995-01-01 AND DynamicFilter [ empty ], pruning_predicate=l_shipdate_null_count@1 != row_count@2 AND l_shipdate_max@0 >= 1994-01-01 AND l_shipdate_null_count@1 != row_count@2 AND l_shipdate_min@3 < 1995-01-01, required_guarantees=[] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/14.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/4.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/9.parquet:..]]}, projection=[l_partkey, l_suppkey, l_quantity, l_shipdate], file_type=parquet, predicate=l_shipdate@10 >= 1994-01-01 AND l_shipdate@10 < 1995-01-01 AND DynamicFilter [ empty ], pruning_predicate=l_shipdate_null_count@1 != row_count@2 AND l_shipdate_max@0 >= 1994-01-01 AND l_shipdate_null_count@1 != row_count@2 AND l_shipdate_min@3 < 1995-01-01, required_guarantees=[] + └────────────────────────────────────────────────── "); Ok(()) } @@ -1251,68 +1278,91 @@ mod tests { #[tokio::test] async fn test_tpch_21() -> Result<(), Box> { let plan = test_tpch_query("q21").await?; - assert_snapshot!(plan, @r" + assert_snapshot!(plan, @" ┌───── DistributedExec │ SortPreservingMergeExec: [numwait@1 DESC, s_name@0 ASC NULLS LAST] - │ SortExec: expr=[numwait@1 DESC, s_name@0 ASC NULLS LAST], preserve_partitioning=[true] - │ ProjectionExec: expr=[s_name@0 as s_name, count(Int64(1))@1 as numwait] - │ AggregateExec: mode=FinalPartitioned, gby=[s_name@0 as s_name], aggr=[count(Int64(1))] - │ RepartitionExec: partitioning=Hash([s_name@0], 3), input_partitions=3 - │ AggregateExec: mode=Partial, gby=[s_name@0 as s_name], aggr=[count(Int64(1))] - │ HashJoinExec: mode=CollectLeft, join_type=LeftAnti, on=[(l_orderkey@1, l_orderkey@0)], filter=l_suppkey@1 != l_suppkey@0, projection=[s_name@0] - │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftSemi, on=[(l_orderkey@1, l_orderkey@0)], filter=l_suppkey@1 != l_suppkey@0 - │ CoalescePartitionsExec - │ [Stage 4] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., ...], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., ...], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., ...]]}, projection=[l_orderkey, l_suppkey], file_type=parquet, predicate=DynamicFilter [ empty ] - │ FilterExec: l_receiptdate@3 > l_commitdate@2, projection=[l_orderkey@0, l_suppkey@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., ...], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., ...], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., ...]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + │ [Stage 9] => NetworkCoalesceExec: output_partitions=9, input_tasks=3 └────────────────────────────────────────────────── - ┌───── Stage 4 ── tasks=4, partitions=12 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(n_nationkey@0, s_nationkey@1)], projection=[s_name@1, l_orderkey@3, l_suppkey@4] - │ CoalescePartitionsExec - │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(o_orderkey@0, l_orderkey@2)], projection=[s_name@1, s_nationkey@2, l_orderkey@3, l_suppkey@4] - │ CoalescePartitionsExec - │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(s_suppkey@0, l_suppkey@1)], projection=[s_name@1, s_nationkey@2, l_orderkey@3, l_suppkey@4] - │ CoalescePartitionsExec - │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 - │ FilterExec: l_receiptdate@3 > l_commitdate@2, projection=[l_orderkey@0, l_suppkey@1] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/14.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/4.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/9.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + ┌───── Stage 9 ── tasks=3, partitions=3 + │ SortExec: expr=[numwait@1 DESC, s_name@0 ASC NULLS LAST], preserve_partitioning=[true] + │ ProjectionExec: expr=[s_name@0 as s_name, count(Int64(1))@1 as numwait] + │ AggregateExec: mode=FinalPartitioned, gby=[s_name@0 as s_name], aggr=[count(Int64(1))] + │ [Stage 8] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: n_name@1 = SAUDI ARABIA, projection=[n_nationkey@0] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/1.parquet:.., /testdata/tpch/plan_sf0.02/nation/10.parquet:..], [/testdata/tpch/plan_sf0.02/nation/14.parquet:.., /testdata/tpch/plan_sf0.02/nation/15.parquet:..], [/testdata/tpch/plan_sf0.02/nation/4.parquet:.., /testdata/tpch/plan_sf0.02/nation/5.parquet:.., /testdata/tpch/plan_sf0.02/nation/6.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = SAUDI ARABIA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= SAUDI ARABIA AND SAUDI ARABIA <= n_name_max@1, required_guarantees=[n_name in (SAUDI ARABIA)] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/10.parquet:.., /testdata/tpch/plan_sf0.02/nation/11.parquet:..], [/testdata/tpch/plan_sf0.02/nation/15.parquet:.., /testdata/tpch/plan_sf0.02/nation/16.parquet:.., /testdata/tpch/plan_sf0.02/nation/2.parquet:..], [/testdata/tpch/plan_sf0.02/nation/6.parquet:.., /testdata/tpch/plan_sf0.02/nation/7.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = SAUDI ARABIA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= SAUDI ARABIA AND SAUDI ARABIA <= n_name_max@1, required_guarantees=[n_name in (SAUDI ARABIA)] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/11.parquet:.., /testdata/tpch/plan_sf0.02/nation/12.parquet:.., /testdata/tpch/plan_sf0.02/nation/13.parquet:..], [/testdata/tpch/plan_sf0.02/nation/2.parquet:.., /testdata/tpch/plan_sf0.02/nation/3.parquet:..], [/testdata/tpch/plan_sf0.02/nation/7.parquet:.., /testdata/tpch/plan_sf0.02/nation/8.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = SAUDI ARABIA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= SAUDI ARABIA AND SAUDI ARABIA <= n_name_max@1, required_guarantees=[n_name in (SAUDI ARABIA)] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/13.parquet:.., /testdata/tpch/plan_sf0.02/nation/14.parquet:..], [/testdata/tpch/plan_sf0.02/nation/3.parquet:.., /testdata/tpch/plan_sf0.02/nation/4.parquet:..], [/testdata/tpch/plan_sf0.02/nation/8.parquet:.., /testdata/tpch/plan_sf0.02/nation/9.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = SAUDI ARABIA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= SAUDI ARABIA AND SAUDI ARABIA <= n_name_max@1, required_guarantees=[n_name in (SAUDI ARABIA)] - └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ FilterExec: o_orderstatus@1 = F, projection=[o_orderkey@0] - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/1.parquet:.., /testdata/tpch/plan_sf0.02/orders/10.parquet:..], [/testdata/tpch/plan_sf0.02/orders/14.parquet:.., /testdata/tpch/plan_sf0.02/orders/15.parquet:..], [/testdata/tpch/plan_sf0.02/orders/4.parquet:.., /testdata/tpch/plan_sf0.02/orders/5.parquet:..]]}, projection=[o_orderkey, o_orderstatus], file_type=parquet, predicate=o_orderstatus@2 = F, pruning_predicate=o_orderstatus_null_count@2 != row_count@3 AND o_orderstatus_min@0 <= F AND F <= o_orderstatus_max@1, required_guarantees=[o_orderstatus in (F)] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/10.parquet:.., /testdata/tpch/plan_sf0.02/orders/11.parquet:..], [/testdata/tpch/plan_sf0.02/orders/15.parquet:.., /testdata/tpch/plan_sf0.02/orders/16.parquet:.., /testdata/tpch/plan_sf0.02/orders/2.parquet:..], [/testdata/tpch/plan_sf0.02/orders/5.parquet:.., /testdata/tpch/plan_sf0.02/orders/6.parquet:.., /testdata/tpch/plan_sf0.02/orders/7.parquet:..]]}, projection=[o_orderkey, o_orderstatus], file_type=parquet, predicate=o_orderstatus@2 = F, pruning_predicate=o_orderstatus_null_count@2 != row_count@3 AND o_orderstatus_min@0 <= F AND F <= o_orderstatus_max@1, required_guarantees=[o_orderstatus in (F)] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/11.parquet:.., /testdata/tpch/plan_sf0.02/orders/12.parquet:.., /testdata/tpch/plan_sf0.02/orders/13.parquet:..], [/testdata/tpch/plan_sf0.02/orders/2.parquet:.., /testdata/tpch/plan_sf0.02/orders/3.parquet:..], [/testdata/tpch/plan_sf0.02/orders/7.parquet:.., /testdata/tpch/plan_sf0.02/orders/8.parquet:..]]}, projection=[o_orderkey, o_orderstatus], file_type=parquet, predicate=o_orderstatus@2 = F, pruning_predicate=o_orderstatus_null_count@2 != row_count@3 AND o_orderstatus_min@0 <= F AND F <= o_orderstatus_max@1, required_guarantees=[o_orderstatus in (F)] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/13.parquet:.., /testdata/tpch/plan_sf0.02/orders/14.parquet:..], [/testdata/tpch/plan_sf0.02/orders/3.parquet:.., /testdata/tpch/plan_sf0.02/orders/4.parquet:..], [/testdata/tpch/plan_sf0.02/orders/8.parquet:.., /testdata/tpch/plan_sf0.02/orders/9.parquet:..]]}, projection=[o_orderkey, o_orderstatus], file_type=parquet, predicate=o_orderstatus@2 = F, pruning_predicate=o_orderstatus_null_count@2 != row_count@3 AND o_orderstatus_min@0 <= F AND F <= o_orderstatus_max@1, required_guarantees=[o_orderstatus in (F)] - └────────────────────────────────────────────────── - ┌───── Stage 3 ── tasks=4, partitions=48 - │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/1.parquet:.., /testdata/tpch/plan_sf0.02/supplier/10.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/14.parquet:.., /testdata/tpch/plan_sf0.02/supplier/15.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/4.parquet:.., /testdata/tpch/plan_sf0.02/supplier/5.parquet:..]]}, projection=[s_suppkey, s_name, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/10.parquet:.., /testdata/tpch/plan_sf0.02/supplier/11.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/15.parquet:.., /testdata/tpch/plan_sf0.02/supplier/16.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/5.parquet:.., /testdata/tpch/plan_sf0.02/supplier/6.parquet:.., /testdata/tpch/plan_sf0.02/supplier/7.parquet:..]]}, projection=[s_suppkey, s_name, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/11.parquet:.., /testdata/tpch/plan_sf0.02/supplier/12.parquet:.., /testdata/tpch/plan_sf0.02/supplier/13.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/16.parquet:.., /testdata/tpch/plan_sf0.02/supplier/2.parquet:.., /testdata/tpch/plan_sf0.02/supplier/3.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/7.parquet:.., /testdata/tpch/plan_sf0.02/supplier/8.parquet:..]]}, projection=[s_suppkey, s_name, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/13.parquet:.., /testdata/tpch/plan_sf0.02/supplier/14.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/3.parquet:.., /testdata/tpch/plan_sf0.02/supplier/4.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/8.parquet:.., /testdata/tpch/plan_sf0.02/supplier/9.parquet:..]]}, projection=[s_suppkey, s_name, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] + ┌───── Stage 8 ── tasks=4, partitions=9 + │ RepartitionExec: partitioning=Hash([s_name@0], 9), input_partitions=3 + │ AggregateExec: mode=Partial, gby=[s_name@0 as s_name], aggr=[count(Int64(1))] + │ HashJoinExec: mode=Partitioned, join_type=LeftAnti, on=[(l_orderkey@1, l_orderkey@0)], filter=l_suppkey@1 != l_suppkey@0, projection=[s_name@0] + │ [Stage 6] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 7] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── + ┌───── Stage 6 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([l_orderkey@1], 12), input_partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftSemi, on=[(l_orderkey@1, l_orderkey@0)], filter=l_suppkey@1 != l_suppkey@0 + │ [Stage 4] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 5] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([l_orderkey@1], 12), input_partitions=3 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(n_nationkey@0, s_nationkey@1)], projection=[s_name@1, l_orderkey@3, l_suppkey@4] + │ CoalescePartitionsExec + │ [Stage 1] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(o_orderkey@0, l_orderkey@2)], projection=[s_name@1, s_nationkey@2, l_orderkey@3, l_suppkey@4] + │ CoalescePartitionsExec + │ [Stage 2] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ HashJoinExec: mode=CollectLeft, join_type=Inner, on=[(s_suppkey@0, l_suppkey@1)], projection=[s_name@1, s_nationkey@2, l_orderkey@3, l_suppkey@4] + │ CoalescePartitionsExec + │ [Stage 3] => NetworkBroadcastExec: partitions_per_consumer=3, stage_partitions=12, input_tasks=4 + │ FilterExec: l_receiptdate@3 > l_commitdate@2, projection=[l_orderkey@0, l_suppkey@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/14.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/4.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/9.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 1 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: n_name@1 = SAUDI ARABIA, projection=[n_nationkey@0] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/1.parquet:.., /testdata/tpch/plan_sf0.02/nation/10.parquet:..], [/testdata/tpch/plan_sf0.02/nation/14.parquet:.., /testdata/tpch/plan_sf0.02/nation/15.parquet:..], [/testdata/tpch/plan_sf0.02/nation/4.parquet:.., /testdata/tpch/plan_sf0.02/nation/5.parquet:.., /testdata/tpch/plan_sf0.02/nation/6.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = SAUDI ARABIA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= SAUDI ARABIA AND SAUDI ARABIA <= n_name_max@1, required_guarantees=[n_name in (SAUDI ARABIA)] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/10.parquet:.., /testdata/tpch/plan_sf0.02/nation/11.parquet:..], [/testdata/tpch/plan_sf0.02/nation/15.parquet:.., /testdata/tpch/plan_sf0.02/nation/16.parquet:.., /testdata/tpch/plan_sf0.02/nation/2.parquet:..], [/testdata/tpch/plan_sf0.02/nation/6.parquet:.., /testdata/tpch/plan_sf0.02/nation/7.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = SAUDI ARABIA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= SAUDI ARABIA AND SAUDI ARABIA <= n_name_max@1, required_guarantees=[n_name in (SAUDI ARABIA)] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/11.parquet:.., /testdata/tpch/plan_sf0.02/nation/12.parquet:.., /testdata/tpch/plan_sf0.02/nation/13.parquet:..], [/testdata/tpch/plan_sf0.02/nation/2.parquet:.., /testdata/tpch/plan_sf0.02/nation/3.parquet:..], [/testdata/tpch/plan_sf0.02/nation/7.parquet:.., /testdata/tpch/plan_sf0.02/nation/8.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = SAUDI ARABIA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= SAUDI ARABIA AND SAUDI ARABIA <= n_name_max@1, required_guarantees=[n_name in (SAUDI ARABIA)] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/nation/13.parquet:.., /testdata/tpch/plan_sf0.02/nation/14.parquet:..], [/testdata/tpch/plan_sf0.02/nation/3.parquet:.., /testdata/tpch/plan_sf0.02/nation/4.parquet:..], [/testdata/tpch/plan_sf0.02/nation/8.parquet:.., /testdata/tpch/plan_sf0.02/nation/9.parquet:..]]}, projection=[n_nationkey, n_name], file_type=parquet, predicate=n_name@1 = SAUDI ARABIA, pruning_predicate=n_name_null_count@2 != row_count@3 AND n_name_min@0 <= SAUDI ARABIA AND SAUDI ARABIA <= n_name_max@1, required_guarantees=[n_name in (SAUDI ARABIA)] + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ FilterExec: o_orderstatus@1 = F, projection=[o_orderkey@0] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/1.parquet:.., /testdata/tpch/plan_sf0.02/orders/10.parquet:..], [/testdata/tpch/plan_sf0.02/orders/14.parquet:.., /testdata/tpch/plan_sf0.02/orders/15.parquet:..], [/testdata/tpch/plan_sf0.02/orders/4.parquet:.., /testdata/tpch/plan_sf0.02/orders/5.parquet:..]]}, projection=[o_orderkey, o_orderstatus], file_type=parquet, predicate=o_orderstatus@2 = F, pruning_predicate=o_orderstatus_null_count@2 != row_count@3 AND o_orderstatus_min@0 <= F AND F <= o_orderstatus_max@1, required_guarantees=[o_orderstatus in (F)] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/10.parquet:.., /testdata/tpch/plan_sf0.02/orders/11.parquet:..], [/testdata/tpch/plan_sf0.02/orders/15.parquet:.., /testdata/tpch/plan_sf0.02/orders/16.parquet:.., /testdata/tpch/plan_sf0.02/orders/2.parquet:..], [/testdata/tpch/plan_sf0.02/orders/5.parquet:.., /testdata/tpch/plan_sf0.02/orders/6.parquet:.., /testdata/tpch/plan_sf0.02/orders/7.parquet:..]]}, projection=[o_orderkey, o_orderstatus], file_type=parquet, predicate=o_orderstatus@2 = F, pruning_predicate=o_orderstatus_null_count@2 != row_count@3 AND o_orderstatus_min@0 <= F AND F <= o_orderstatus_max@1, required_guarantees=[o_orderstatus in (F)] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/11.parquet:.., /testdata/tpch/plan_sf0.02/orders/12.parquet:.., /testdata/tpch/plan_sf0.02/orders/13.parquet:..], [/testdata/tpch/plan_sf0.02/orders/2.parquet:.., /testdata/tpch/plan_sf0.02/orders/3.parquet:..], [/testdata/tpch/plan_sf0.02/orders/7.parquet:.., /testdata/tpch/plan_sf0.02/orders/8.parquet:..]]}, projection=[o_orderkey, o_orderstatus], file_type=parquet, predicate=o_orderstatus@2 = F, pruning_predicate=o_orderstatus_null_count@2 != row_count@3 AND o_orderstatus_min@0 <= F AND F <= o_orderstatus_max@1, required_guarantees=[o_orderstatus in (F)] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/13.parquet:.., /testdata/tpch/plan_sf0.02/orders/14.parquet:..], [/testdata/tpch/plan_sf0.02/orders/3.parquet:.., /testdata/tpch/plan_sf0.02/orders/4.parquet:..], [/testdata/tpch/plan_sf0.02/orders/8.parquet:.., /testdata/tpch/plan_sf0.02/orders/9.parquet:..]]}, projection=[o_orderkey, o_orderstatus], file_type=parquet, predicate=o_orderstatus@2 = F, pruning_predicate=o_orderstatus_null_count@2 != row_count@3 AND o_orderstatus_min@0 <= F AND F <= o_orderstatus_max@1, required_guarantees=[o_orderstatus in (F)] + └────────────────────────────────────────────────── + ┌───── Stage 3 ── tasks=4, partitions=48 + │ BroadcastExec: input_partitions=3, consumer_tasks=4, output_partitions=12 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/1.parquet:.., /testdata/tpch/plan_sf0.02/supplier/10.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/14.parquet:.., /testdata/tpch/plan_sf0.02/supplier/15.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/4.parquet:.., /testdata/tpch/plan_sf0.02/supplier/5.parquet:..]]}, projection=[s_suppkey, s_name, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/10.parquet:.., /testdata/tpch/plan_sf0.02/supplier/11.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/15.parquet:.., /testdata/tpch/plan_sf0.02/supplier/16.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/5.parquet:.., /testdata/tpch/plan_sf0.02/supplier/6.parquet:.., /testdata/tpch/plan_sf0.02/supplier/7.parquet:..]]}, projection=[s_suppkey, s_name, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/11.parquet:.., /testdata/tpch/plan_sf0.02/supplier/12.parquet:.., /testdata/tpch/plan_sf0.02/supplier/13.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/16.parquet:.., /testdata/tpch/plan_sf0.02/supplier/2.parquet:.., /testdata/tpch/plan_sf0.02/supplier/3.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/7.parquet:.., /testdata/tpch/plan_sf0.02/supplier/8.parquet:..]]}, projection=[s_suppkey, s_name, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/supplier/13.parquet:.., /testdata/tpch/plan_sf0.02/supplier/14.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/3.parquet:.., /testdata/tpch/plan_sf0.02/supplier/4.parquet:..], [/testdata/tpch/plan_sf0.02/supplier/8.parquet:.., /testdata/tpch/plan_sf0.02/supplier/9.parquet:..]]}, projection=[s_suppkey, s_name, s_nationkey], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 5 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([l_orderkey@0], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:..]]}, projection=[l_orderkey, l_suppkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:..]]}, projection=[l_orderkey, l_suppkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:..]]}, projection=[l_orderkey, l_suppkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/14.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/4.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/9.parquet:..]]}, projection=[l_orderkey, l_suppkey], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 7 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([l_orderkey@0], 12), input_partitions=3 + │ FilterExec: l_receiptdate@3 > l_commitdate@2, projection=[l_orderkey@0, l_suppkey@1] + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/1.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/10.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/14.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/15.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/4.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/5.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/10.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/11.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/15.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/16.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/5.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/6.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/7.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/11.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/12.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/13.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/16.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/2.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/3.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/7.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/8.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/lineitem/13.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/14.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/3.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/4.parquet:..], [/testdata/tpch/plan_sf0.02/lineitem/8.parquet:.., /testdata/tpch/plan_sf0.02/lineitem/9.parquet:..]]}, projection=[l_orderkey, l_suppkey, l_commitdate, l_receiptdate], file_type=parquet, predicate=l_receiptdate@12 > l_commitdate@11 AND DynamicFilter [ empty ] + └────────────────────────────────────────────────── "); Ok(()) } @@ -1320,7 +1370,7 @@ mod tests { #[tokio::test] async fn test_tpch_22() -> Result<(), Box> { let plan = test_tpch_query("q22").await?; - assert_snapshot!(plan, @r" + assert_snapshot!(plan, @" ┌───── DistributedExec │ SortPreservingMergeExec: [cntrycode@0 ASC NULLS LAST] │ SortExec: expr=[cntrycode@0 ASC NULLS LAST], preserve_partitioning=[true] @@ -1335,24 +1385,34 @@ mod tests { │ BroadcastExec: input_partitions=1, consumer_tasks=1, output_partitions=1 │ ProjectionExec: expr=[c_phone@0 as c_phone, c_acctbal@1 as c_acctbal, CAST(c_acctbal@1 AS Decimal128(19, 6)) as join_proj_push_down_1] │ CoalescePartitionsExec - │ HashJoinExec: mode=CollectLeft, join_type=LeftAnti, on=[(c_custkey@0, o_custkey@0)], projection=[c_phone@1, c_acctbal@2] - │ CoalescePartitionsExec - │ [Stage 1] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/1.parquet:.., /testdata/tpch/plan_sf0.02/orders/10.parquet:.., /testdata/tpch/plan_sf0.02/orders/11.parquet:.., /testdata/tpch/plan_sf0.02/orders/12.parquet:.., /testdata/tpch/plan_sf0.02/orders/13.parquet:.., ...], [/testdata/tpch/plan_sf0.02/orders/14.parquet:.., /testdata/tpch/plan_sf0.02/orders/15.parquet:.., /testdata/tpch/plan_sf0.02/orders/16.parquet:.., /testdata/tpch/plan_sf0.02/orders/2.parquet:.., /testdata/tpch/plan_sf0.02/orders/3.parquet:.., ...], [/testdata/tpch/plan_sf0.02/orders/4.parquet:.., /testdata/tpch/plan_sf0.02/orders/5.parquet:.., /testdata/tpch/plan_sf0.02/orders/6.parquet:.., /testdata/tpch/plan_sf0.02/orders/7.parquet:.., /testdata/tpch/plan_sf0.02/orders/8.parquet:.., ...]]}, projection=[o_custkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ [Stage 3] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 │ AggregateExec: mode=Final, gby=[], aggr=[avg(customer.c_acctbal)] │ CoalescePartitionsExec - │ [Stage 2] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 + │ [Stage 4] => NetworkCoalesceExec: output_partitions=12, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 1 ── tasks=4, partitions=12 - │ FilterExec: substr(c_phone@1, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) - │ DistributedLeafExec: - │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/1.parquet:.., /testdata/tpch/plan_sf0.02/customer/10.parquet:..], [/testdata/tpch/plan_sf0.02/customer/14.parquet:.., /testdata/tpch/plan_sf0.02/customer/15.parquet:..], [/testdata/tpch/plan_sf0.02/customer/4.parquet:.., /testdata/tpch/plan_sf0.02/customer/5.parquet:.., /testdata/tpch/plan_sf0.02/customer/6.parquet:..]]}, projection=[c_custkey, c_phone, c_acctbal], file_type=parquet, predicate=substr(c_phone@4, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) - │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/10.parquet:.., /testdata/tpch/plan_sf0.02/customer/11.parquet:..], [/testdata/tpch/plan_sf0.02/customer/15.parquet:.., /testdata/tpch/plan_sf0.02/customer/16.parquet:..], [/testdata/tpch/plan_sf0.02/customer/6.parquet:.., /testdata/tpch/plan_sf0.02/customer/7.parquet:..]]}, projection=[c_custkey, c_phone, c_acctbal], file_type=parquet, predicate=substr(c_phone@4, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) - │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/11.parquet:.., /testdata/tpch/plan_sf0.02/customer/12.parquet:.., /testdata/tpch/plan_sf0.02/customer/13.parquet:..], [/testdata/tpch/plan_sf0.02/customer/16.parquet:.., /testdata/tpch/plan_sf0.02/customer/2.parquet:.., /testdata/tpch/plan_sf0.02/customer/3.parquet:..], [/testdata/tpch/plan_sf0.02/customer/7.parquet:.., /testdata/tpch/plan_sf0.02/customer/8.parquet:..]]}, projection=[c_custkey, c_phone, c_acctbal], file_type=parquet, predicate=substr(c_phone@4, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) - │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/13.parquet:.., /testdata/tpch/plan_sf0.02/customer/14.parquet:..], [/testdata/tpch/plan_sf0.02/customer/3.parquet:.., /testdata/tpch/plan_sf0.02/customer/4.parquet:..], [/testdata/tpch/plan_sf0.02/customer/8.parquet:.., /testdata/tpch/plan_sf0.02/customer/9.parquet:..]]}, projection=[c_custkey, c_phone, c_acctbal], file_type=parquet, predicate=substr(c_phone@4, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) + ┌───── Stage 3 ── tasks=4, partitions=3 + │ HashJoinExec: mode=Partitioned, join_type=LeftAnti, on=[(c_custkey@0, o_custkey@0)], projection=[c_phone@1, c_acctbal@2] + │ [Stage 1] => NetworkShuffleExec: output_partitions=3, input_tasks=4 + │ [Stage 2] => NetworkShuffleExec: output_partitions=3, input_tasks=4 └────────────────────────────────────────────────── - ┌───── Stage 2 ── tasks=4, partitions=12 + ┌───── Stage 1 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([c_custkey@0], 12), input_partitions=3 + │ FilterExec: substr(c_phone@1, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/1.parquet:.., /testdata/tpch/plan_sf0.02/customer/10.parquet:..], [/testdata/tpch/plan_sf0.02/customer/14.parquet:.., /testdata/tpch/plan_sf0.02/customer/15.parquet:..], [/testdata/tpch/plan_sf0.02/customer/4.parquet:.., /testdata/tpch/plan_sf0.02/customer/5.parquet:.., /testdata/tpch/plan_sf0.02/customer/6.parquet:..]]}, projection=[c_custkey, c_phone, c_acctbal], file_type=parquet, predicate=substr(c_phone@4, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/10.parquet:.., /testdata/tpch/plan_sf0.02/customer/11.parquet:..], [/testdata/tpch/plan_sf0.02/customer/15.parquet:.., /testdata/tpch/plan_sf0.02/customer/16.parquet:..], [/testdata/tpch/plan_sf0.02/customer/6.parquet:.., /testdata/tpch/plan_sf0.02/customer/7.parquet:..]]}, projection=[c_custkey, c_phone, c_acctbal], file_type=parquet, predicate=substr(c_phone@4, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/11.parquet:.., /testdata/tpch/plan_sf0.02/customer/12.parquet:.., /testdata/tpch/plan_sf0.02/customer/13.parquet:..], [/testdata/tpch/plan_sf0.02/customer/16.parquet:.., /testdata/tpch/plan_sf0.02/customer/2.parquet:.., /testdata/tpch/plan_sf0.02/customer/3.parquet:..], [/testdata/tpch/plan_sf0.02/customer/7.parquet:.., /testdata/tpch/plan_sf0.02/customer/8.parquet:..]]}, projection=[c_custkey, c_phone, c_acctbal], file_type=parquet, predicate=substr(c_phone@4, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/customer/13.parquet:.., /testdata/tpch/plan_sf0.02/customer/14.parquet:..], [/testdata/tpch/plan_sf0.02/customer/3.parquet:.., /testdata/tpch/plan_sf0.02/customer/4.parquet:..], [/testdata/tpch/plan_sf0.02/customer/8.parquet:.., /testdata/tpch/plan_sf0.02/customer/9.parquet:..]]}, projection=[c_custkey, c_phone, c_acctbal], file_type=parquet, predicate=substr(c_phone@4, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]) + └────────────────────────────────────────────────── + ┌───── Stage 2 ── tasks=4, partitions=12 + │ RepartitionExec: partitioning=Hash([o_custkey@0], 12), input_partitions=3 + │ DistributedLeafExec: + │ t0: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/1.parquet:.., /testdata/tpch/plan_sf0.02/orders/10.parquet:..], [/testdata/tpch/plan_sf0.02/orders/14.parquet:.., /testdata/tpch/plan_sf0.02/orders/15.parquet:..], [/testdata/tpch/plan_sf0.02/orders/4.parquet:.., /testdata/tpch/plan_sf0.02/orders/5.parquet:..]]}, projection=[o_custkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t1: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/10.parquet:.., /testdata/tpch/plan_sf0.02/orders/11.parquet:..], [/testdata/tpch/plan_sf0.02/orders/15.parquet:.., /testdata/tpch/plan_sf0.02/orders/16.parquet:.., /testdata/tpch/plan_sf0.02/orders/2.parquet:..], [/testdata/tpch/plan_sf0.02/orders/5.parquet:.., /testdata/tpch/plan_sf0.02/orders/6.parquet:.., /testdata/tpch/plan_sf0.02/orders/7.parquet:..]]}, projection=[o_custkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t2: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/11.parquet:.., /testdata/tpch/plan_sf0.02/orders/12.parquet:.., /testdata/tpch/plan_sf0.02/orders/13.parquet:..], [/testdata/tpch/plan_sf0.02/orders/2.parquet:.., /testdata/tpch/plan_sf0.02/orders/3.parquet:..], [/testdata/tpch/plan_sf0.02/orders/7.parquet:.., /testdata/tpch/plan_sf0.02/orders/8.parquet:..]]}, projection=[o_custkey], file_type=parquet, predicate=DynamicFilter [ empty ] + │ t3: DataSourceExec: file_groups={3 groups: [[/testdata/tpch/plan_sf0.02/orders/13.parquet:.., /testdata/tpch/plan_sf0.02/orders/14.parquet:..], [/testdata/tpch/plan_sf0.02/orders/3.parquet:.., /testdata/tpch/plan_sf0.02/orders/4.parquet:..], [/testdata/tpch/plan_sf0.02/orders/8.parquet:.., /testdata/tpch/plan_sf0.02/orders/9.parquet:..]]}, projection=[o_custkey], file_type=parquet, predicate=DynamicFilter [ empty ] + └────────────────────────────────────────────────── + ┌───── Stage 4 ── tasks=4, partitions=12 │ AggregateExec: mode=Partial, gby=[], aggr=[avg(customer.c_acctbal)] │ FilterExec: c_acctbal@1 > Some(0),15,2 AND substr(c_phone@0, 1, 2) IN (SET) ([13, 31, 23, 29, 30, 18, 17]), projection=[c_acctbal@1] │ DistributedLeafExec: