Search in sources :

Example 11 with StatsProvider

use of com.facebook.presto.cost.StatsProvider in project presto by prestodb.

the class RuntimeReorderJoinSides method apply.

@Override
public Result apply(JoinNode joinNode, Captures captures, Context context) {
    // Early exit if the leaves of the joinNode subtree include non tableScan nodes.
    if (searchFrom(joinNode, context.getLookup()).where(node -> node.getSources().isEmpty() && !(node instanceof TableScanNode)).matches()) {
        return Result.empty();
    }
    double leftOutputSizeInBytes = Double.NaN;
    double rightOutputSizeInBytes = Double.NaN;
    StatsProvider statsProvider = context.getStatsProvider();
    if (searchFrom(joinNode, context.getLookup()).where(node -> !(node instanceof TableScanNode) && !(node instanceof ExchangeNode)).findAll().size() == 1) {
        // Simple plan is characterized as Join directly on tableScanNodes only with exchangeNode in between.
        // For simple plans, directly fetch the overall table sizes as the size of the join sides to have
        // accurate input bytes statistics and meanwhile avoid non-negligible cost of collecting and processing
        // per-column statistics.
        leftOutputSizeInBytes = statsProvider.getStats(joinNode.getLeft()).getOutputSizeInBytes();
        rightOutputSizeInBytes = statsProvider.getStats(joinNode.getRight()).getOutputSizeInBytes();
    }
    if (Double.isNaN(leftOutputSizeInBytes) || Double.isNaN(rightOutputSizeInBytes)) {
        // Per-column estimate left and right output size for complex plans or when size statistics is unavailable.
        leftOutputSizeInBytes = statsProvider.getStats(joinNode.getLeft()).getOutputSizeInBytes(joinNode.getLeft().getOutputVariables());
        rightOutputSizeInBytes = statsProvider.getStats(joinNode.getRight()).getOutputSizeInBytes(joinNode.getRight().getOutputVariables());
    }
    if (Double.isNaN(leftOutputSizeInBytes) || Double.isNaN(rightOutputSizeInBytes)) {
        return Result.empty();
    }
    if (rightOutputSizeInBytes <= leftOutputSizeInBytes) {
        return Result.empty();
    }
    // Check if the swapped join is valid.
    if (!isSwappedJoinValid(joinNode)) {
        return Result.empty();
    }
    JoinNode swapped = joinNode.flipChildren();
    PlanNode newLeft = swapped.getLeft();
    Optional<VariableReferenceExpression> leftHashVariable = swapped.getLeftHashVariable();
    // Remove unnecessary LocalExchange in the current probe side. If the immediate left child (new probe side) of the join node
    // is a localExchange, there are two cases: an Exchange introduced by the current probe side (previous build side); or it is a UnionNode.
    // If the exchangeNode has more than 1 sources, it corresponds to the second case, otherwise it corresponds to the first case and could be safe to remove
    PlanNode resolvedSwappedLeft = context.getLookup().resolve(newLeft);
    if (resolvedSwappedLeft instanceof ExchangeNode && resolvedSwappedLeft.getSources().size() == 1) {
        // Ensure the new probe after skipping the local exchange will satisfy the required probe side property
        if (checkProbeSidePropertySatisfied(resolvedSwappedLeft.getSources().get(0), context)) {
            newLeft = resolvedSwappedLeft.getSources().get(0);
            // it as the leftHashVariable of the swapped join node.
            if (swapped.getLeftHashVariable().isPresent()) {
                int hashVariableIndex = resolvedSwappedLeft.getOutputVariables().indexOf(swapped.getLeftHashVariable().get());
                leftHashVariable = Optional.of(resolvedSwappedLeft.getSources().get(0).getOutputVariables().get(hashVariableIndex));
                // This is against typical iterativeOptimizer behavior and given this case is rare, just abort the swapping for this scenario.
                if (swapped.getOutputVariables().contains(swapped.getLeftHashVariable().get())) {
                    return Result.empty();
                }
            }
        }
    }
    // Add additional localExchange if the new build side does not satisfy the partitioning conditions.
    List<VariableReferenceExpression> buildJoinVariables = swapped.getCriteria().stream().map(JoinNode.EquiJoinClause::getRight).collect(toImmutableList());
    PlanNode newRight = swapped.getRight();
    if (!checkBuildSidePropertySatisfied(swapped.getRight(), buildJoinVariables, context)) {
        if (getTaskConcurrency(context.getSession()) > 1) {
            newRight = systemPartitionedExchange(context.getIdAllocator().getNextId(), LOCAL, swapped.getRight(), buildJoinVariables, swapped.getRightHashVariable());
        } else {
            newRight = gatheringExchange(context.getIdAllocator().getNextId(), LOCAL, swapped.getRight());
        }
    }
    JoinNode newJoinNode = new JoinNode(swapped.getSourceLocation(), swapped.getId(), swapped.getType(), newLeft, newRight, swapped.getCriteria(), swapped.getOutputVariables(), swapped.getFilter(), leftHashVariable, swapped.getRightHashVariable(), swapped.getDistributionType(), swapped.getDynamicFilters());
    log.debug(format("Probe size: %.2f is smaller than Build size: %.2f => invoke runtime join swapping on JoinNode ID: %s.", leftOutputSizeInBytes, rightOutputSizeInBytes, newJoinNode.getId()));
    return Result.ofPlanNode(newJoinNode);
}
Also used : ExchangeNode.systemPartitionedExchange(com.facebook.presto.sql.planner.plan.ExchangeNode.systemPartitionedExchange) Logger(com.facebook.airlift.log.Logger) StreamPropertyDerivations(com.facebook.presto.sql.planner.optimizations.StreamPropertyDerivations) Captures(com.facebook.presto.matching.Captures) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) StreamPreferredProperties.exactlyPartitionedOn(com.facebook.presto.sql.planner.optimizations.StreamPreferredProperties.exactlyPartitionedOn) Patterns.join(com.facebook.presto.sql.planner.plan.Patterns.join) Pattern(com.facebook.presto.matching.Pattern) StreamPreferredProperties.fixedParallelism(com.facebook.presto.sql.planner.optimizations.StreamPreferredProperties.fixedParallelism) LOCAL(com.facebook.presto.sql.planner.plan.ExchangeNode.Scope.LOCAL) Objects.requireNonNull(java.util.Objects.requireNonNull) SystemSessionProperties.isJoinSpillingEnabled(com.facebook.presto.SystemSessionProperties.isJoinSpillingEnabled) StreamPreferredProperties.singleStream(com.facebook.presto.sql.planner.optimizations.StreamPreferredProperties.singleStream) SystemSessionProperties.getTaskConcurrency(com.facebook.presto.SystemSessionProperties.getTaskConcurrency) PlanNodeSearcher.searchFrom(com.facebook.presto.sql.planner.optimizations.PlanNodeSearcher.searchFrom) ExchangeNode.gatheringExchange(com.facebook.presto.sql.planner.plan.ExchangeNode.gatheringExchange) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) Rule(com.facebook.presto.sql.planner.iterative.Rule) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) StatsProvider(com.facebook.presto.cost.StatsProvider) String.format(java.lang.String.format) SqlParser(com.facebook.presto.sql.parser.SqlParser) StreamPreferredProperties.defaultParallelism(com.facebook.presto.sql.planner.optimizations.StreamPreferredProperties.defaultParallelism) RIGHT(com.facebook.presto.sql.planner.plan.JoinNode.Type.RIGHT) SystemSessionProperties.isSpillEnabled(com.facebook.presto.SystemSessionProperties.isSpillEnabled) PlanNode(com.facebook.presto.spi.plan.PlanNode) List(java.util.List) REPLICATED(com.facebook.presto.sql.planner.plan.JoinNode.DistributionType.REPLICATED) LEFT(com.facebook.presto.sql.planner.plan.JoinNode.Type.LEFT) TableScanNode(com.facebook.presto.spi.plan.TableScanNode) StreamProperties(com.facebook.presto.sql.planner.optimizations.StreamPropertyDerivations.StreamProperties) StreamPreferredProperties(com.facebook.presto.sql.planner.optimizations.StreamPreferredProperties) Optional(java.util.Optional) PARTITIONED(com.facebook.presto.sql.planner.plan.JoinNode.DistributionType.PARTITIONED) Metadata(com.facebook.presto.metadata.Metadata) ExchangeNode(com.facebook.presto.sql.planner.plan.ExchangeNode) PlanNode(com.facebook.presto.spi.plan.PlanNode) TableScanNode(com.facebook.presto.spi.plan.TableScanNode) StatsProvider(com.facebook.presto.cost.StatsProvider) ExchangeNode(com.facebook.presto.sql.planner.plan.ExchangeNode) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression)

Example 12 with StatsProvider

use of com.facebook.presto.cost.StatsProvider in project presto by prestodb.

the class PushPartialAggregationThroughExchange method partialAggregationNotUseful.

private boolean partialAggregationNotUseful(AggregationNode aggregationNode, ExchangeNode exchangeNode, Context context) {
    StatsProvider stats = context.getStatsProvider();
    PlanNodeStatsEstimate exchangeStats = stats.getStats(exchangeNode);
    PlanNodeStatsEstimate aggregationStats = stats.getStats(aggregationNode);
    double inputBytes = exchangeStats.getOutputSizeInBytes(exchangeNode.getOutputVariables());
    double outputBytes = aggregationStats.getOutputSizeInBytes(aggregationNode.getOutputVariables());
    double byteReductionThreshold = getPartialAggregationByteReductionThreshold(context.getSession());
    return exchangeStats.isConfident() && outputBytes > inputBytes * byteReductionThreshold;
}
Also used : StatsProvider(com.facebook.presto.cost.StatsProvider) PlanNodeStatsEstimate(com.facebook.presto.cost.PlanNodeStatsEstimate)

Example 13 with StatsProvider

use of com.facebook.presto.cost.StatsProvider in project presto by prestodb.

the class LogicalPlanner method computeStats.

private StatsAndCosts computeStats(PlanNode root, TypeProvider types) {
    if (explain || isPrintStatsForNonJoinQuery(session) || PlanNodeSearcher.searchFrom(root).where(node -> (node instanceof JoinNode) || (node instanceof SemiJoinNode)).matches()) {
        StatsProvider statsProvider = new CachingStatsProvider(statsCalculator, session, types);
        CostProvider costProvider = new CachingCostProvider(costCalculator, statsProvider, Optional.empty(), session);
        return StatsAndCosts.create(root, statsProvider, costProvider);
    }
    return StatsAndCosts.empty();
}
Also used : CachingStatsProvider(com.facebook.presto.cost.CachingStatsProvider) CachingStatsProvider(com.facebook.presto.cost.CachingStatsProvider) StatsProvider(com.facebook.presto.cost.StatsProvider) SemiJoinNode(com.facebook.presto.sql.planner.plan.SemiJoinNode) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) CachingCostProvider(com.facebook.presto.cost.CachingCostProvider) CostProvider(com.facebook.presto.cost.CostProvider) CachingCostProvider(com.facebook.presto.cost.CachingCostProvider) SemiJoinNode(com.facebook.presto.sql.planner.plan.SemiJoinNode)

Example 14 with StatsProvider

use of com.facebook.presto.cost.StatsProvider in project presto by prestodb.

the class MarkDistinctMatcher method detailMatches.

@Override
public MatchResult detailMatches(PlanNode node, StatsProvider stats, Session session, Metadata metadata, SymbolAliases symbolAliases) {
    checkState(shapeMatches(node), "Plan testing framework error: shapeMatches returned false in detailMatches in %s", this.getClass().getName());
    MarkDistinctNode markDistinctNode = (MarkDistinctNode) node;
    if (!markDistinctNode.getHashVariable().map(variable -> new Symbol(variable.getName())).equals(hashSymbol.map(alias -> alias.toSymbol(symbolAliases)))) {
        return NO_MATCH;
    }
    if (!markDistinctNode.getDistinctVariables().stream().map(VariableReferenceExpression::getName).map(Symbol::new).collect(toImmutableSet()).equals(distinctSymbols.stream().map(alias -> alias.toSymbol(symbolAliases)).collect(toImmutableSet()))) {
        return NO_MATCH;
    }
    return match(markerSymbol.toString(), createSymbolReference(markDistinctNode.getMarkerVariable()));
}
Also used : Session(com.facebook.presto.Session) StatsProvider(com.facebook.presto.cost.StatsProvider) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression) Preconditions.checkState(com.google.common.base.Preconditions.checkState) PlanNode(com.facebook.presto.spi.plan.PlanNode) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) Symbol(com.facebook.presto.sql.planner.Symbol) MatchResult.match(com.facebook.presto.sql.planner.assertions.MatchResult.match) Objects.requireNonNull(java.util.Objects.requireNonNull) Optional(java.util.Optional) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) NO_MATCH(com.facebook.presto.sql.planner.assertions.MatchResult.NO_MATCH) Metadata(com.facebook.presto.metadata.Metadata) MarkDistinctNode(com.facebook.presto.spi.plan.MarkDistinctNode) ExpressionTreeUtils.createSymbolReference(com.facebook.presto.sql.analyzer.ExpressionTreeUtils.createSymbolReference) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) MarkDistinctNode(com.facebook.presto.spi.plan.MarkDistinctNode) Symbol(com.facebook.presto.sql.planner.Symbol) VariableReferenceExpression(com.facebook.presto.spi.relation.VariableReferenceExpression)

Example 15 with StatsProvider

use of com.facebook.presto.cost.StatsProvider in project presto by prestodb.

the class JoinMatcher method detailMatches.

@Override
public MatchResult detailMatches(PlanNode node, StatsProvider stats, Session session, Metadata metadata, SymbolAliases symbolAliases) {
    checkState(shapeMatches(node), "Plan testing framework error: shapeMatches returned false in detailMatches in %s", this.getClass().getName());
    JoinNode joinNode = (JoinNode) node;
    if (joinNode.getCriteria().size() != equiCriteria.size()) {
        return NO_MATCH;
    }
    if (filter.isPresent()) {
        if (!joinNode.getFilter().isPresent()) {
            return NO_MATCH;
        }
        RowExpression expression = joinNode.getFilter().get();
        if (isExpression(expression)) {
            if (!new ExpressionVerifier(symbolAliases).process(castToExpression(expression), filter.get())) {
                return NO_MATCH;
            }
        } else {
            if (!new RowExpressionVerifier(symbolAliases, metadata, session).process(filter.get(), expression)) {
                return NO_MATCH;
            }
        }
    } else {
        if (joinNode.getFilter().isPresent()) {
            return NO_MATCH;
        }
    }
    if (distributionType.isPresent() && !distributionType.equals(joinNode.getDistributionType())) {
        return NO_MATCH;
    }
    /*
         * Have to use order-independent comparison; there are no guarantees what order
         * the equi criteria will have after planning and optimizing.
         */
    Set<List<String>> actual = joinNode.getCriteria().stream().map(criteria -> ImmutableList.of(criteria.getLeft().getName(), criteria.getRight().getName())).collect(toImmutableSet());
    Set<List<String>> expected = equiCriteria.stream().map(maker -> maker.getExpectedValue(symbolAliases)).map(criteria -> ImmutableList.of(criteria.getLeft().getName(), criteria.getRight().getName())).collect(toImmutableSet());
    if (!expected.equals(actual)) {
        return NO_MATCH;
    }
    if (dynamicFilter.isPresent() && !dynamicFilter.get().match(joinNode, symbolAliases).isMatch()) {
        return NO_MATCH;
    }
    return MatchResult.match();
}
Also used : RowExpression(com.facebook.presto.spi.relation.RowExpression) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) OriginalExpressionUtils.isExpression(com.facebook.presto.sql.relational.OriginalExpressionUtils.isExpression) Session(com.facebook.presto.Session) StatsProvider(com.facebook.presto.cost.StatsProvider) Set(java.util.Set) Preconditions.checkState(com.google.common.base.Preconditions.checkState) PlanNode(com.facebook.presto.spi.plan.PlanNode) List(java.util.List) OriginalExpressionUtils.castToExpression(com.facebook.presto.sql.relational.OriginalExpressionUtils.castToExpression) Expression(com.facebook.presto.sql.tree.Expression) ImmutableList(com.google.common.collect.ImmutableList) Objects.requireNonNull(java.util.Objects.requireNonNull) Optional(java.util.Optional) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) NO_MATCH(com.facebook.presto.sql.planner.assertions.MatchResult.NO_MATCH) Metadata(com.facebook.presto.metadata.Metadata) DistributionType(com.facebook.presto.sql.planner.plan.JoinNode.DistributionType) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) JoinNode(com.facebook.presto.sql.planner.plan.JoinNode) RowExpression(com.facebook.presto.spi.relation.RowExpression) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList)

Aggregations

StatsProvider (com.facebook.presto.cost.StatsProvider)16 Metadata (com.facebook.presto.metadata.Metadata)8 PlanNode (com.facebook.presto.spi.plan.PlanNode)8 List (java.util.List)8 Session (com.facebook.presto.Session)7 NO_MATCH (com.facebook.presto.sql.planner.assertions.MatchResult.NO_MATCH)7 MoreObjects.toStringHelper (com.google.common.base.MoreObjects.toStringHelper)7 Preconditions.checkState (com.google.common.base.Preconditions.checkState)7 Objects.requireNonNull (java.util.Objects.requireNonNull)7 Optional (java.util.Optional)7 VariableReferenceExpression (com.facebook.presto.spi.relation.VariableReferenceExpression)6 MatchResult.match (com.facebook.presto.sql.planner.assertions.MatchResult.match)6 CachingStatsProvider (com.facebook.presto.cost.CachingStatsProvider)5 Symbol (com.facebook.presto.sql.planner.Symbol)5 CachingCostProvider (com.facebook.presto.cost.CachingCostProvider)4 CostProvider (com.facebook.presto.cost.CostProvider)4 ImmutableSet.toImmutableSet (com.google.common.collect.ImmutableSet.toImmutableSet)4 PlanMatchPattern.node (com.facebook.presto.sql.planner.assertions.PlanMatchPattern.node)3 JoinNode (com.facebook.presto.sql.planner.plan.JoinNode)3 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)3