Repository: calcite Updated Branches: refs/heads/master cb8376b13 -> 879139fc6
[CALCITE-2104] Add variants of AggregateUnionAggregateRule that match left and right inputs of Union, to reduce matching cost in VolcanoPlanner (lincoln-lil) Close apache/calcite#589 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/879139fc Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/879139fc Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/879139fc Branch: refs/heads/master Commit: 879139fc616ae954f5ebcbd53cb3b23c239a9a92 Parents: cb8376b Author: lincoln-lil <[email protected]> Authored: Thu Dec 21 15:38:57 2017 +0800 Committer: Julian Hyde <[email protected]> Committed: Sun Dec 24 22:43:33 2017 -0800 ---------------------------------------------------------------------- .../rel/rules/AggregateUnionAggregateRule.java | 48 +++++++++++++++----- .../apache/calcite/test/RelOptRulesTest.java | 34 ++++++++++---- .../org/apache/calcite/test/RelOptRulesTest.xml | 27 +++++++++++ 3 files changed, 88 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/879139fc/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java index 8eeaaa7..a15d74a 100644 --- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java +++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateUnionAggregateRule.java @@ -39,9 +39,31 @@ import org.apache.calcite.tools.RelBuilderFactory; * still have only two inputs. */ public class AggregateUnionAggregateRule extends RelOptRule { + /** Instance that matches an {@code Aggregate} as the left input of + * {@code Union}. */ + public static final AggregateUnionAggregateRule AGG_ON_FIRST_INPUT = + new AggregateUnionAggregateRule(LogicalAggregate.class, LogicalUnion.class, + LogicalAggregate.class, RelNode.class, RelFactories.LOGICAL_BUILDER, + "AggregateUnionAggregateRule:first-input-agg"); + + /** Instance that matches an {@code Aggregate} as the right input of + * {@code Union}. */ + public static final AggregateUnionAggregateRule AGG_ON_SECOND_INPUT = + new AggregateUnionAggregateRule(LogicalAggregate.class, LogicalUnion.class, + RelNode.class, LogicalAggregate.class, RelFactories.LOGICAL_BUILDER, + "AggregateUnionAggregateRule:second-input-agg"); + + /** Instance that matches an {@code Aggregate} as either input of + * {@link Union}. + * + * <p>Because it matches {@link RelNode} for each input of {@code Union}, it + * will create O(N ^ 2) matches, which may cost too much during the popMatch + * phase in VolcanoPlanner. If efficiency is a concern, we recommend that you + * use {@link #AGG_ON_FIRST_INPUT} and {@link #AGG_ON_SECOND_INPUT} instead. */ public static final AggregateUnionAggregateRule INSTANCE = new AggregateUnionAggregateRule(LogicalAggregate.class, - LogicalUnion.class, RelFactories.LOGICAL_BUILDER); + LogicalUnion.class, RelNode.class, RelNode.class, + RelFactories.LOGICAL_BUILDER, "AggregateUnionAggregateRule"); //~ Constructors ----------------------------------------------------------- @@ -49,13 +71,17 @@ public class AggregateUnionAggregateRule extends RelOptRule { * Creates a AggregateUnionAggregateRule. */ public AggregateUnionAggregateRule(Class<? extends Aggregate> aggregateClass, - Class<? extends Union> unionClass, RelBuilderFactory relBuilderFactory) { + Class<? extends Union> unionClass, + Class<? extends RelNode> firstUnionInputClass, + Class<? extends RelNode> secondUnionInputClass, + RelBuilderFactory relBuilderFactory, + String desc) { super( operand(aggregateClass, null, Aggregate.IS_SIMPLE, operand(unionClass, - operand(RelNode.class, any()), - operand(RelNode.class, any()))), - relBuilderFactory, null); + operand(firstUnionInputClass, any()), + operand(secondUnionInputClass, any()))), + relBuilderFactory, desc); } @Deprecated // to be removed before 2.0 @@ -63,8 +89,9 @@ public class AggregateUnionAggregateRule extends RelOptRule { RelFactories.AggregateFactory aggregateFactory, Class<? extends Union> unionClass, RelFactories.SetOpFactory setOpFactory) { - this(aggregateClass, unionClass, - RelBuilder.proto(aggregateFactory, setOpFactory)); + this(aggregateClass, unionClass, RelNode.class, RelNode.class, + RelBuilder.proto(aggregateFactory, setOpFactory), + "AggregateUnionAggregateRule"); } //~ Methods ---------------------------------------------------------------- @@ -78,18 +105,15 @@ public class AggregateUnionAggregateRule extends RelOptRule { return; } - // We want to apply this rule on the pattern where the LogicalAggregate - // is the second input into the Union first. Hence, that's why the - // rule pattern matches on generic RelNodes rather than explicit - // UnionRels. By doing so, and firing this rule in a bottom-up order, - // it allows us to only specify a single pattern for this rule. final RelBuilder relBuilder = call.builder(); final Aggregate bottomAggRel; if (call.rel(3) instanceof Aggregate) { + // Aggregate is the second input bottomAggRel = call.rel(3); relBuilder.push(call.rel(2)) .push(call.rel(3).getInput(0)); } else if (call.rel(2) instanceof Aggregate) { + // Aggregate is the first input bottomAggRel = call.rel(2); relBuilder.push(call.rel(2).getInput(0)) .push(call.rel(3)); http://git-wip-us.apache.org/repos/asf/calcite/blob/879139fc/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java index 321d9fc..a738a00 100644 --- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java @@ -2514,19 +2514,35 @@ public class RelOptRulesTest extends RelOptTestBase { + "group by rollup(x, y)"); } - @Test public void testPullAggregateThroughUnion() throws Exception { + @Test public void testPullAggregateThroughUnion() { HepProgram program = new HepProgramBuilder() .addRuleInstance(AggregateUnionAggregateRule.INSTANCE) .build(); - checkPlanning(program, - "select deptno, job from" - + " (select deptno, job from emp as e1" - + " group by deptno,job" - + " union all" - + " select deptno, job from emp as e2" - + " group by deptno,job)" - + " group by deptno,job"); + final String sql = "select deptno, job from" + + " (select deptno, job from emp as e1" + + " group by deptno,job" + + " union all" + + " select deptno, job from emp as e2" + + " group by deptno,job)" + + " group by deptno,job"; + sql(sql).with(program).check(); + } + + @Test public void testPullAggregateThroughUnion2() { + HepProgram program = new HepProgramBuilder() + .addRuleInstance(AggregateUnionAggregateRule.AGG_ON_SECOND_INPUT) + .addRuleInstance(AggregateUnionAggregateRule.AGG_ON_FIRST_INPUT) + .build(); + + final String sql = "select deptno, job from" + + " (select deptno, job from emp as e1" + + " group by deptno,job" + + " union all" + + " select deptno, job from emp as e2" + + " group by deptno,job)" + + " group by deptno,job"; + sql(sql).with(program).check(); } private void transitiveInference(RelOptRule... extraRules) throws Exception { http://git-wip-us.apache.org/repos/asf/calcite/blob/879139fc/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml ---------------------------------------------------------------------- diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml index 46518f9..d573517 100644 --- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml @@ -5035,6 +5035,33 @@ LogicalAggregate(group=[{0, 1}]) ]]> </Resource> </TestCase> + <TestCase name="testPullAggregateThroughUnion2"> + <Resource name="sql"> + <![CDATA[select deptno, job from (select deptno, job from emp as e1 group by deptno,job union all select deptno, job from emp as e2 group by deptno,job) group by deptno,job]]> + </Resource> + <Resource name="planBefore"> + <![CDATA[ +LogicalAggregate(group=[{0, 1}]) + LogicalUnion(all=[true]) + LogicalAggregate(group=[{0, 1}]) + LogicalProject(DEPTNO=[$7], JOB=[$2]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + LogicalAggregate(group=[{0, 1}]) + LogicalProject(DEPTNO=[$7], JOB=[$2]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + <Resource name="planAfter"> + <![CDATA[ +LogicalAggregate(group=[{0, 1}]) + LogicalUnion(all=[true]) + LogicalProject(DEPTNO=[$7], JOB=[$2]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) + LogicalProject(DEPTNO=[$7], JOB=[$2]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) +]]> + </Resource> + </TestCase> <TestCase name="testProjectWindowTransposeRule"> <Resource name="sql"> <![CDATA[select count(empno) over(), deptno from emp]]>
