Search in sources :

Example 1 with JoinGraph

use of io.trino.sql.planner.optimizations.joins.JoinGraph in project trino by trinodb.

the class EliminateCrossJoins method getJoinOrder.

/**
 * Given JoinGraph determine the order of joins between graph nodes
 * by traversing JoinGraph. Any graph traversal algorithm could be used
 * here (like BFS or DFS), but we use PriorityQueue to preserve
 * original JoinOrder as mush as it is possible. PriorityQueue returns
 * next nodes to join in order of their occurrence in original Plan.
 */
public static List<Integer> getJoinOrder(JoinGraph graph) {
    ImmutableList.Builder<PlanNode> joinOrder = ImmutableList.builder();
    Map<PlanNodeId, Integer> priorities = new HashMap<>();
    for (int i = 0; i < graph.size(); i++) {
        priorities.put(graph.getNode(i).getId(), i);
    }
    PriorityQueue<PlanNode> nodesToVisit = new PriorityQueue<>(graph.size(), comparing(node -> priorities.get(node.getId())));
    Set<PlanNode> visited = new HashSet<>();
    nodesToVisit.add(graph.getNode(0));
    while (!nodesToVisit.isEmpty()) {
        PlanNode node = nodesToVisit.poll();
        if (!visited.contains(node)) {
            visited.add(node);
            joinOrder.add(node);
            for (JoinGraph.Edge edge : graph.getEdges(node)) {
                nodesToVisit.add(edge.getTargetNode());
            }
        }
        if (nodesToVisit.isEmpty() && visited.size() < graph.size()) {
            // disconnected graph, find new starting point
            Optional<PlanNode> firstNotVisitedNode = graph.getNodes().stream().filter(graphNode -> !visited.contains(graphNode)).findFirst();
            firstNotVisitedNode.ifPresent(nodesToVisit::add);
        }
    }
    checkState(visited.size() == graph.size());
    return joinOrder.build().stream().map(node -> priorities.get(node.getId())).collect(toImmutableList());
}
Also used : JoinGraph(io.trino.sql.planner.optimizations.joins.JoinGraph) PriorityQueue(java.util.PriorityQueue) HashMap(java.util.HashMap) ELIMINATE_CROSS_JOINS(io.trino.sql.planner.OptimizerConfig.JoinReorderingStrategy.ELIMINATE_CROSS_JOINS) FilterNode(io.trino.sql.planner.plan.FilterNode) PlanNode(io.trino.sql.planner.plan.PlanNode) HashSet(java.util.HashSet) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) ImmutableList(com.google.common.collect.ImmutableList) PlanNodeId(io.trino.sql.planner.plan.PlanNodeId) JoinReorderingStrategy(io.trino.sql.planner.OptimizerConfig.JoinReorderingStrategy) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) Rule(io.trino.sql.planner.iterative.Rule) Comparator.comparing(java.util.Comparator.comparing) JoinNode(io.trino.sql.planner.plan.JoinNode) Patterns.join(io.trino.sql.planner.plan.Patterns.join) Symbol(io.trino.sql.planner.Symbol) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableMap(com.google.common.collect.ImmutableMap) SystemSessionProperties.getJoinReorderingStrategy(io.trino.SystemSessionProperties.getJoinReorderingStrategy) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Set(java.util.Set) Preconditions.checkState(com.google.common.base.Preconditions.checkState) List(java.util.List) Pattern(io.trino.matching.Pattern) TypeAnalyzer(io.trino.sql.planner.TypeAnalyzer) Captures(io.trino.matching.Captures) Util.restrictOutputs(io.trino.sql.planner.iterative.rule.Util.restrictOutputs) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) PlanNodeIdAllocator(io.trino.sql.planner.PlanNodeIdAllocator) Session(io.trino.Session) PlannerContext(io.trino.sql.PlannerContext) AUTOMATIC(io.trino.sql.planner.OptimizerConfig.JoinReorderingStrategy.AUTOMATIC) HashMap(java.util.HashMap) ImmutableList(com.google.common.collect.ImmutableList) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) PriorityQueue(java.util.PriorityQueue) JoinGraph(io.trino.sql.planner.optimizations.joins.JoinGraph) PlanNodeId(io.trino.sql.planner.plan.PlanNodeId) PlanNode(io.trino.sql.planner.plan.PlanNode) HashSet(java.util.HashSet)

Example 2 with JoinGraph

use of io.trino.sql.planner.optimizations.joins.JoinGraph in project trino by trinodb.

the class TestEliminateCrossJoins method testDoNotReorderCrossJoins.

@Test
public void testDoNotReorderCrossJoins() {
    Session session = testSessionBuilder().build();
    PlanNode plan = joinNode(joinNode(values("a"), values("b")), values("c"), "b", "c");
    JoinGraph joinGraph = JoinGraph.buildFrom(tester().getPlannerContext(), plan, noLookup(), new PlanNodeIdAllocator(), session, createTestingTypeAnalyzer(tester().getPlannerContext()), TypeProvider.empty());
    assertEquals(getJoinOrder(joinGraph), ImmutableList.of(0, 1, 2));
}
Also used : PlanNode(io.trino.sql.planner.plan.PlanNode) PlanNodeIdAllocator(io.trino.sql.planner.PlanNodeIdAllocator) Session(io.trino.Session) JoinGraph(io.trino.sql.planner.optimizations.joins.JoinGraph) Test(org.testng.annotations.Test) BaseRuleTest(io.trino.sql.planner.iterative.rule.test.BaseRuleTest)

Example 3 with JoinGraph

use of io.trino.sql.planner.optimizations.joins.JoinGraph in project trino by trinodb.

the class TestEliminateCrossJoins method testJoinOrder.

@Test
public void testJoinOrder() {
    Session session = testSessionBuilder().build();
    PlanNode plan = joinNode(joinNode(values("a"), values("b")), values("c"), "a", "c", "b", "c");
    JoinGraph joinGraph = JoinGraph.buildFrom(tester().getPlannerContext(), plan, noLookup(), new PlanNodeIdAllocator(), session, createTestingTypeAnalyzer(tester().getPlannerContext()), TypeProvider.empty());
    assertEquals(getJoinOrder(joinGraph), ImmutableList.of(0, 2, 1));
}
Also used : PlanNode(io.trino.sql.planner.plan.PlanNode) PlanNodeIdAllocator(io.trino.sql.planner.PlanNodeIdAllocator) Session(io.trino.Session) JoinGraph(io.trino.sql.planner.optimizations.joins.JoinGraph) Test(org.testng.annotations.Test) BaseRuleTest(io.trino.sql.planner.iterative.rule.test.BaseRuleTest)

Example 4 with JoinGraph

use of io.trino.sql.planner.optimizations.joins.JoinGraph in project trino by trinodb.

the class TestEliminateCrossJoins method testJoinOrderWithRealCrossJoin.

@Test
public void testJoinOrderWithRealCrossJoin() {
    Session session = testSessionBuilder().build();
    PlanNode leftPlan = joinNode(joinNode(values("a"), values("b")), values("c"), "a", "c", "b", "c");
    PlanNode rightPlan = joinNode(joinNode(values("x"), values("y")), values("z"), "x", "z", "y", "z");
    PlanNode plan = joinNode(leftPlan, rightPlan);
    JoinGraph joinGraph = JoinGraph.buildFrom(tester().getPlannerContext(), plan, noLookup(), new PlanNodeIdAllocator(), session, createTestingTypeAnalyzer(tester().getPlannerContext()), TypeProvider.empty());
    assertEquals(getJoinOrder(joinGraph), ImmutableList.of(0, 2, 1, 3, 5, 4));
}
Also used : PlanNode(io.trino.sql.planner.plan.PlanNode) PlanNodeIdAllocator(io.trino.sql.planner.PlanNodeIdAllocator) Session(io.trino.Session) JoinGraph(io.trino.sql.planner.optimizations.joins.JoinGraph) Test(org.testng.annotations.Test) BaseRuleTest(io.trino.sql.planner.iterative.rule.test.BaseRuleTest)

Example 5 with JoinGraph

use of io.trino.sql.planner.optimizations.joins.JoinGraph in project trino by trinodb.

the class EliminateCrossJoins method apply.

@Override
public Result apply(JoinNode node, Captures captures, Context context) {
    JoinGraph joinGraph = JoinGraph.buildFrom(plannerContext, node, context.getLookup(), context.getIdAllocator(), context.getSession(), typeAnalyzer, context.getSymbolAllocator().getTypes());
    if (joinGraph.size() < 3 || !joinGraph.isContainsCrossJoin()) {
        return Result.empty();
    }
    List<Integer> joinOrder = getJoinOrder(joinGraph);
    if (isOriginalOrder(joinOrder)) {
        return Result.empty();
    }
    PlanNode replacement = buildJoinTree(node.getOutputSymbols(), joinGraph, joinOrder, context.getIdAllocator());
    return Result.ofPlanNode(replacement);
}
Also used : PlanNode(io.trino.sql.planner.plan.PlanNode) JoinGraph(io.trino.sql.planner.optimizations.joins.JoinGraph)

Aggregations

JoinGraph (io.trino.sql.planner.optimizations.joins.JoinGraph)8 PlanNode (io.trino.sql.planner.plan.PlanNode)8 Session (io.trino.Session)6 PlanNodeIdAllocator (io.trino.sql.planner.PlanNodeIdAllocator)6 BaseRuleTest (io.trino.sql.planner.iterative.rule.test.BaseRuleTest)5 Test (org.testng.annotations.Test)5 ImmutableList (com.google.common.collect.ImmutableList)2 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)2 FilterNode (io.trino.sql.planner.plan.FilterNode)2 JoinNode (io.trino.sql.planner.plan.JoinNode)2 PlanNodeId (io.trino.sql.planner.plan.PlanNodeId)2 Expression (io.trino.sql.tree.Expression)2 HashSet (java.util.HashSet)2 Preconditions.checkArgument (com.google.common.base.Preconditions.checkArgument)1 Preconditions.checkState (com.google.common.base.Preconditions.checkState)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 ImmutableSet (com.google.common.collect.ImmutableSet)1 SystemSessionProperties.getJoinReorderingStrategy (io.trino.SystemSessionProperties.getJoinReorderingStrategy)1 Captures (io.trino.matching.Captures)1 Pattern (io.trino.matching.Pattern)1