You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@calcite.apache.org by Juri Petersen <ju...@apache.org> on 2025/06/10 05:17:22 UTC
Pushing all Filters into Joins
Hello,
I am in need of some help or guidance.
We are currently trying to parse Join-Order-Benchmark queries into plans with Apache Calcite.
The following query is our input:
SELECT MIN(t.title) AS movie_title
FROM postgres.company_name AS cn,
postgres.keyword AS k,
postgres.movie_companies AS mc,
postgres.movie_keyword AS mk,
postgres.title AS t
WHERE cn.country_code ='[de]'
AND k.keyword ='character-name-in-title'
AND cn.id = mc.company_id
AND mc.movie_id = t.id
AND t.id = mk.movie_id
AND mk.keyword_id = k.id
AND mc.movie_id = mk.movie_id;
This is being parsed into the following RelNode:
LogicalAggregate(group=[{}], movie_title=[MIN($0)])
LogicalProject(title=[$19])
LogicalFilter(condition=[AND(=($2, '[de]'), =($8, 'character-name-in-title'), =($0, $12), =($11, $18), =($18, $16), =($17, $7), =($11, $16))])
LogicalJoin(condition=[true], joinType=[inner])
LogicalJoin(condition=[true], joinType=[inner])
LogicalJoin(condition=[true], joinType=[inner])
LogicalJoin(condition=[true], joinType=[inner])
LogicalTableScan(table=[[postgres, company_name]])
LogicalTableScan(table=[[postgres, keyword]])
LogicalTableScan(table=[[postgres, movie_companies]])
LogicalTableScan(table=[[postgres, movie_keyword]])
LogicalTableScan(table=[[postgres, title]])
I can observe that there are only 4 joins at this point in time. After this, we optimize the plan with the following RuleSet:
(
CoreRules.JOIN_PUSH_TRANSITIVE_PREDICATES,
CoreRules.JOIN_CONDITION_PUSH,
CoreRules.FILTER_INTO_JOIN,
CoreRules.JOIN_ASSOCIATE
)
However, the resuliting plan looks like this:
WayangAggregate(group=[{}], movie_title=[MIN($0)])
WayangProject(title=[$19])
WayangJoin(condition=[=($11, $18)], joinType=[inner])
WayangJoin(condition=[=($0, $12)], joinType=[inner])
WayangFilter(condition=[=($2, '[de]')])
WayangTableScan(table=[[postgres, company_name]])
WayangJoin(condition=[=($10, $0)], joinType=[inner])
WayangFilter(condition=[=($1, 'character-name-in-title')])
WayangTableScan(table=[[postgres, keyword]])
WayangJoin(condition=[=($1, $6)], joinType=[inner])
WayangTableScan(table=[[postgres, movie_companies]])
WayangTableScan(table=[[postgres, movie_keyword]])
WayangTableScan(table=[[postgres, title]])
My problem with this is that the original Filter has more than 4 join conditions, but only 4 joins are being created and some of the Join conditions are never pushed down or applied.
I am either just misunderstanding why this happens or am missing a rule to enforce the pushdown/usage of all conditions or instantiation of all joins.
Can anybody give me some pointers?
Thanks in advance for your help!
Best,
Juri
Re: Pushing all Filters into Joins
Posted by Steven Phillips <st...@dremio.com.INVALID>.
The original filter has 5 join conditions, but 3 of them are mutually
dependent: $11 = $18, $18 = $16, $11 = $16
So there are really only 4 join conditions, which is what you end up with.
On Mon, Jun 9, 2025 at 10:17 PM Juri Petersen <ju...@apache.org> wrote:
> Hello,
> I am in need of some help or guidance.
> We are currently trying to parse Join-Order-Benchmark queries into plans
> with Apache Calcite.
> The following query is our input:
>
> SELECT MIN(t.title) AS movie_title
> FROM postgres.company_name AS cn,
> postgres.keyword AS k,
> postgres.movie_companies AS mc,
> postgres.movie_keyword AS mk,
> postgres.title AS t
> WHERE cn.country_code ='[de]'
> AND k.keyword ='character-name-in-title'
> AND cn.id = mc.company_id
> AND mc.movie_id = t.id
> AND t.id = mk.movie_id
> AND mk.keyword_id = k.id
> AND mc.movie_id = mk.movie_id;
>
> This is being parsed into the following RelNode:
>
> LogicalAggregate(group=[{}], movie_title=[MIN($0)])
> LogicalProject(title=[$19])
> LogicalFilter(condition=[AND(=($2, '[de]'), =($8,
> 'character-name-in-title'), =($0, $12), =($11, $18), =($18, $16), =($17,
> $7), =($11, $16))])
> LogicalJoin(condition=[true], joinType=[inner])
> LogicalJoin(condition=[true], joinType=[inner])
> LogicalJoin(condition=[true], joinType=[inner])
> LogicalJoin(condition=[true], joinType=[inner])
> LogicalTableScan(table=[[postgres, company_name]])
> LogicalTableScan(table=[[postgres, keyword]])
> LogicalTableScan(table=[[postgres, movie_companies]])
> LogicalTableScan(table=[[postgres, movie_keyword]])
> LogicalTableScan(table=[[postgres, title]])
>
> I can observe that there are only 4 joins at this point in time. After
> this, we optimize the plan with the following RuleSet:
>
> (
> CoreRules.JOIN_PUSH_TRANSITIVE_PREDICATES,
> CoreRules.JOIN_CONDITION_PUSH,
> CoreRules.FILTER_INTO_JOIN,
> CoreRules.JOIN_ASSOCIATE
> )
>
> However, the resuliting plan looks like this:
>
> WayangAggregate(group=[{}], movie_title=[MIN($0)])
> WayangProject(title=[$19])
> WayangJoin(condition=[=($11, $18)], joinType=[inner])
> WayangJoin(condition=[=($0, $12)], joinType=[inner])
> WayangFilter(condition=[=($2, '[de]')])
> WayangTableScan(table=[[postgres, company_name]])
> WayangJoin(condition=[=($10, $0)], joinType=[inner])
> WayangFilter(condition=[=($1, 'character-name-in-title')])
> WayangTableScan(table=[[postgres, keyword]])
> WayangJoin(condition=[=($1, $6)], joinType=[inner])
> WayangTableScan(table=[[postgres, movie_companies]])
> WayangTableScan(table=[[postgres, movie_keyword]])
> WayangTableScan(table=[[postgres, title]])
>
> My problem with this is that the original Filter has more than 4 join
> conditions, but only 4 joins are being created and some of the Join
> conditions are never pushed down or applied.
> I am either just misunderstanding why this happens or am missing a rule to
> enforce the pushdown/usage of all conditions or instantiation of all joins.
> Can anybody give me some pointers?
>
> Thanks in advance for your help!
>
> Best,
> Juri
>