Avoid unnecessary exchange and partial aggregation in correlated scalar subquery and correlated IN predicate
See original GitHub issueFor a correlated scalar subquery like
select name, (select max(name) from region where regionkey = nation.regionkey) from nation;
we currently produce the following plan (i’m using set session push_aggregation_through_join = false;
to have the plan more readable)
- Output[name, _col1] => [name:varchar(25), max:varchar(25)]
_col1 := max
- RemoteExchange[GATHER] => name:varchar(25), max:varchar(25)
- Project[] => [name:varchar(25), max:varchar(25)]
x - Aggregate(FINAL)[name, regionkey, unique][$hashvalue] => [name:varchar(25), regionkey:bigint, unique:bigint, $hashvalue:bigint, max:varchar(25)]
x max := "max"("max_17")
x - LocalExchange[HASH][$hashvalue] ("name", "regionkey", "unique") => name:varchar(25), regionkey:bigint, unique:bigint, max_17:varbinary, $hashvalue:bigint
x - Aggregate(PARTIAL)[name, regionkey, unique][$hashvalue_23] => [name:varchar(25), regionkey:bigint, unique:bigint, $hashvalue_23:bigint, max_17:varbinary]
x max_17 := "max"("name_1")
- Project[] => [name:varchar(25), regionkey:bigint, unique:bigint, name_1:varchar(25), $hashvalue_23:bigint]
$hashvalue_23 := "combine_hash"("combine_hash"("combine_hash"(BIGINT '0', COALESCE("$operator$hash_code"("name"), 0)), COALESCE("$operator$hash_code"("regionkey"), 0)), COALESCE("$operator$hash_code"("unique"), 0))
- LeftJoin[("regionkey" = "regionkey_0")][$hashvalue_18, $hashvalue_20] => [name:varchar(25), regionkey:bigint, unique:bigint, name_1:varchar(25)]
- RemoteExchange[REPARTITION][$hashvalue_18] => name:varchar(25), regionkey:bigint, unique:bigint, $hashvalue_18:bigint
- Project[] => [name:varchar(25), regionkey:bigint, unique:bigint, $hashvalue_19:bigint]
$hashvalue_19 := "combine_hash"(BIGINT '0', COALESCE("$operator$hash_code"("regionkey"), 0))
- AssignUniqueId => [name:varchar(25), regionkey:bigint, unique:bigint]
- TableScan[tpch:tpch:nation:sf0.01, originalConstraint = true] => [name:varchar(25), regionkey:bigint]
name := tpch:name
regionkey := tpch:regionkey
- LocalExchange[HASH][$hashvalue_20] ("regionkey_0") => regionkey_0:bigint, name_1:varchar(25), $hashvalue_20:bigint
- RemoteExchange[REPARTITION][$hashvalue_21] => regionkey_0:bigint, name_1:varchar(25), $hashvalue_21:bigint
- ScanProject[table = tpch:tpch:region:sf0.01, originalConstraint = true] => [regionkey_0:bigint, name_1:varchar(25), $hashvalue_22:bigint]
$hashvalue_22 := "combine_hash"(BIGINT '0', COALESCE("$operator$hash_code"("regionkey_0"), 0))
regionkey_0 := tpch:regionkey
name_1 := tpch:name
the part marked has redundant local exchange and partial aggregation. Since the aggregation’s group contains unique symbol assigned before join then, at least as long the aggregation remains above the join, no exchange is needed. Values with same group key will be in the same split (pipeline) anyway. The marked group could be replaced with single step aggregation (and no exchange).
Same applies to correlated IN predicates.
cc @kokosing
Issue Analytics
- State:
- Created 6 years ago
- Comments:20 (19 by maintainers)
Top Results From Across the Web
Avoid using correlated subqueries. Consider using JOIN instead
The rule checks for usage of correlated subqueries. Unless the query optimizer re-writes the correlated subquery with a join, the correlated subquery has...
Read more >What does "Correlated scalar subqueries must be Aggregated ...
I use Spark 2.0. I'd like to execute the following SQL query: val sqlText = """ select f.ID as TID, f.BldgID as TBldgID,...
Read more >Correlated scalar subqueries in Apache Spark SQL
This post focuses on correlated scalar subqueries in Apache Spark SQL and presents them in 3 sections. The first two show some sample ......
Read more >Practical planning and execution of groupjoin and nested ...
For the general case, we deliberately introduce a groupjoin to separately calculate the aggregates of the correlated subquery, filter ...
Read more >A Practical Approach to Groupjoin and Nested Aggregates
separately calculate the aggregates of the correlated subquery, filter unnecessary tuples, and avoid the COUNT bug [48]. Figure 3 shows.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
It must support parallel local execution to work correctly, because it is executed in parallel within a task. There is:
com.facebook.presto.operator.AssignUniqueIdOperator#rowIdPool
.Strict order is not required (my mistake, corrected previous posts), just information that rows are ordered should be enough.
Probe rows that pass though
LeftJoin
won’t be unique, but they will be ordered on all columns viaunique_id
.Supporting
AssignUniqueId
inActualProperties
will allow to avoid remote exchange before aggregation ifAssignUniqueId
is in source stage. See your example: https://github.com/prestodb/presto/issues/8171#issuecomment-387549439 It is also needed so that SINGLE aggregation can be later converted into STREAMING whenAssignUniqueId
is in source stage.Supporting
AssignUniqueId
inStreamProperties
is needed so that you can convertSINGLE
aggregation intoSTREAMING
. Note thatSINGLE->STREAMING
conversion is a local decision on a pipeline level (stream needs to be partitioned and ordered)It does support that by my knowledge, @kokosing ?
@sopel39 @martint Karol, Martin, #10731 builds on top of #10681 and adds streaming support to
HashAggregationOperator
, updates[Stream]PropertyDerivations
to setpartitioned_on(unique)
andgrouped(unique)
properties, and uses these inAddLocalExchanges
to plan streaming aggregations.