From ca36dc697f0fb0fd25085cf4f01db215848ae87a Mon Sep 17 00:00:00 2001 From: Mingyu Chen Date: Thu, 7 May 2020 09:30:30 +0800 Subject: [PATCH] [Bug] Fix bug that push down logic error on semi join (#3481) For SQL like: ``` select * from join1 left semi join join2 on join1.id = join2.id and join2.id > 1; ``` the predicate `join2.id > 1` can not be pushed down to table join1. --- .../org/apache/doris/analysis/Analyzer.java | 8 ++- .../apache/doris/planner/QueryPlanTest.java | 55 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/fe/src/main/java/org/apache/doris/analysis/Analyzer.java b/fe/src/main/java/org/apache/doris/analysis/Analyzer.java index 1f565ceae9..dee9d933c6 100644 --- a/fe/src/main/java/org/apache/doris/analysis/Analyzer.java +++ b/fe/src/main/java/org/apache/doris/analysis/Analyzer.java @@ -956,8 +956,9 @@ public class Analyzer { /** - * Return all registered conjuncts that are fully bound by - * given list of tuple ids, the eqJoinConjuncts and inclOjConjuncts is excluded. + * Return all registered conjuncts that are fully bound by given list of tuple ids. + * the eqJoinConjuncts and sjClauseByConjunct is excluded. + * This method is used get conjuncts which may be able to pushed down to scan node. */ public List getConjuncts(List tupleIds) { List result = Lists.newArrayList(); @@ -968,8 +969,9 @@ public class Analyzer { for (Expr e : globalState.conjuncts.values()) { if (e.isBoundByTupleIds(tupleIds) && !e.isAuxExpr() - && !eqJoinConjunctIds.contains(e.getId()) + && !eqJoinConjunctIds.contains(e.getId()) // to exclude to conjuncts like (A.id = B.id) && !globalState.ojClauseByConjunct.containsKey(e.getId()) + && !globalState.sjClauseByConjunct.containsKey(e.getId()) && canEvalPredicate(tupleIds, e)) { result.add(e); } diff --git a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java index c192d18327..dccd979a23 100644 --- a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java +++ b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java @@ -655,6 +655,61 @@ public class QueryPlanTest { System.out.println(explainString); Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1")); Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1")); + + // test anti join, right table join predicate, only push to right table + sql = "select *\n from join1\n" + + "left anti join join2 on join1.id = join2.id\n" + + "and join2.id > 1;"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1")); + Assert.assertFalse(explainString.contains("PREDICATES: `join1`.`id` > 1")); + + // test semi join, right table join predicate, only push to right table + sql = "select *\n from join1\n" + + "left semi join join2 on join1.id = join2.id\n" + + "and join2.id > 1;"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("PREDICATES: `join2`.`id` > 1")); + Assert.assertFalse(explainString.contains("PREDICATES: `join1`.`id` > 1")); + + // test anti join, left table join predicate, left table couldn't push down + sql = "select *\n from join1\n" + + "left anti join join2 on join1.id = join2.id\n" + + "and join1.id > 1;"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("other join predicates: `join1`.`id` > 1")); + Assert.assertFalse(explainString.contains("PREDICATES: `join1`.`id` > 1")); + + // test semi join, left table join predicate, only push to left table + sql = "select *\n from join1\n" + + "left semi join join2 on join1.id = join2.id\n" + + "and join1.id > 1;"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1")); + + // test anti join, left table where predicate, only push to left table + sql = "select join1.id\n" + + "from join1\n" + + "left anti join join2 on join1.id = join2.id\n" + + "where join1.id > 1;"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1")); + Assert.assertFalse(explainString.contains("PREDICATES: `join2`.`id` > 1")); + + // test semi join, left table where predicate, only push to left table + sql = "select join1.id\n" + + "from join1\n" + + "left semi join join2 on join1.id = join2.id\n" + + "where join1.id > 1;"; + explainString = UtFrameUtils.getSQLPlanOrErrorMsg(connectContext, "explain " + sql); + System.out.println(explainString); + Assert.assertTrue(explainString.contains("PREDICATES: `join1`.`id` > 1")); + Assert.assertFalse(explainString.contains("PREDICATES: `join2`.`id` > 1")); } @Test