Search in sources :

Example 1 with StatsProvider

use of io.trino.cost.StatsProvider in project trino by trinodb.

the class DetermineSemiJoinDistributionType method getSemiJoinNodeWithCost.

private PlanNodeWithCost getSemiJoinNodeWithCost(SemiJoinNode possibleJoinNode, Context context) {
    TypeProvider types = context.getSymbolAllocator().getTypes();
    StatsProvider stats = context.getStatsProvider();
    boolean replicated = possibleJoinNode.getDistributionType().get() == REPLICATED;
    /*
         *   HACK!
         *
         *   Currently cost model always has to compute the total cost of an operation.
         *   For SEMI-JOIN the total cost consist of 4 parts:
         *     - Cost of exchanges that have to be introduced to execute a JOIN
         *     - Cost of building a hash table
         *     - Cost of probing a hash table
         *     - Cost of building an output for matched rows
         *
         *   When output size for a SEMI-JOIN cannot be estimated the cost model returns
         *   UNKNOWN cost for the join.
         *
         *   However assuming the cost of SEMI-JOIN output is always the same, we can still make
         *   cost based decisions based on the input cost for different types of SEMI-JOINs.
         *
         *   TODO Decision about the distribution should be based on LocalCostEstimate only when PlanCostEstimate cannot be calculated. Otherwise cost comparator cannot take query.max-memory into account.
         */
    int estimatedSourceDistributedTaskCount = taskCountEstimator.estimateSourceDistributedTaskCount(context.getSession());
    LocalCostEstimate cost = calculateJoinCostWithoutOutput(possibleJoinNode.getSource(), possibleJoinNode.getFilteringSource(), stats, types, replicated, estimatedSourceDistributedTaskCount);
    return new PlanNodeWithCost(cost.toPlanCost(), possibleJoinNode);
}
Also used : StatsProvider(io.trino.cost.StatsProvider) TypeProvider(io.trino.sql.planner.TypeProvider) LocalCostEstimate(io.trino.cost.LocalCostEstimate)

Example 2 with StatsProvider

use of io.trino.cost.StatsProvider in project trino by trinodb.

the class PushPredicateIntoTableScan method pushFilterIntoTableScan.

public static Optional<PlanNode> pushFilterIntoTableScan(FilterNode filterNode, TableScanNode node, boolean pruneWithPredicateExpression, Session session, SymbolAllocator symbolAllocator, PlannerContext plannerContext, TypeAnalyzer typeAnalyzer, StatsProvider statsProvider, DomainTranslator domainTranslator) {
    if (!isAllowPushdownIntoConnectors(session)) {
        return Optional.empty();
    }
    SplitExpression splitExpression = splitExpression(plannerContext, filterNode.getPredicate());
    DomainTranslator.ExtractionResult decomposedPredicate = DomainTranslator.getExtractionResult(plannerContext, session, splitExpression.getDeterministicPredicate(), symbolAllocator.getTypes());
    TupleDomain<ColumnHandle> newDomain = decomposedPredicate.getTupleDomain().transformKeys(node.getAssignments()::get).intersect(node.getEnforcedConstraint());
    Map<NodeRef<Expression>, Type> remainingExpressionTypes = typeAnalyzer.getTypes(session, symbolAllocator.getTypes(), decomposedPredicate.getRemainingExpression());
    Optional<ConnectorExpression> connectorExpression = new ConnectorExpressionTranslator.SqlToConnectorExpressionTranslator(session, remainingExpressionTypes, plannerContext).process(decomposedPredicate.getRemainingExpression());
    Map<String, ColumnHandle> connectorExpressionAssignments = connectorExpression.map(ignored -> node.getAssignments().entrySet().stream().collect(toImmutableMap(entry -> entry.getKey().getName(), Map.Entry::getValue))).orElse(ImmutableMap.of());
    Map<ColumnHandle, Symbol> assignments = ImmutableBiMap.copyOf(node.getAssignments()).inverse();
    Constraint constraint;
    // use evaluator only when there is some predicate which could not be translated into tuple domain
    if (pruneWithPredicateExpression && !TRUE_LITERAL.equals(decomposedPredicate.getRemainingExpression())) {
        LayoutConstraintEvaluator evaluator = new LayoutConstraintEvaluator(plannerContext, typeAnalyzer, session, symbolAllocator.getTypes(), node.getAssignments(), combineConjuncts(plannerContext.getMetadata(), splitExpression.getDeterministicPredicate(), // which would be expensive to evaluate in the call to isCandidate below.
        domainTranslator.toPredicate(session, newDomain.simplify().transformKeys(assignments::get))));
        constraint = new Constraint(newDomain, connectorExpression.orElse(TRUE), connectorExpressionAssignments, evaluator::isCandidate, evaluator.getArguments());
    } else {
        // Currently, invoking the expression interpreter is very expensive.
        // TODO invoke the interpreter unconditionally when the interpreter becomes cheap enough.
        constraint = new Constraint(newDomain, connectorExpression.orElse(TRUE), connectorExpressionAssignments);
    }
    // check if new domain is wider than domain already provided by table scan
    if (constraint.predicate().isEmpty() && // TODO do we need to track enforced ConnectorExpression in TableScanNode?
    TRUE.equals(connectorExpression.orElse(TRUE)) && newDomain.contains(node.getEnforcedConstraint())) {
        Expression resultingPredicate = createResultingPredicate(plannerContext, session, symbolAllocator, typeAnalyzer, splitExpression.getDynamicFilter(), TRUE_LITERAL, splitExpression.getNonDeterministicPredicate(), decomposedPredicate.getRemainingExpression());
        if (!TRUE_LITERAL.equals(resultingPredicate)) {
            return Optional.of(new FilterNode(filterNode.getId(), node, resultingPredicate));
        }
        return Optional.of(node);
    }
    if (newDomain.isNone()) {
        // to turn the subtree into a Values node
        return Optional.of(new ValuesNode(node.getId(), node.getOutputSymbols(), ImmutableList.of()));
    }
    Optional<ConstraintApplicationResult<TableHandle>> result = plannerContext.getMetadata().applyFilter(session, node.getTable(), constraint);
    if (result.isEmpty()) {
        return Optional.empty();
    }
    TableHandle newTable = result.get().getHandle();
    TableProperties newTableProperties = plannerContext.getMetadata().getTableProperties(session, newTable);
    Optional<TablePartitioning> newTablePartitioning = newTableProperties.getTablePartitioning();
    if (newTableProperties.getPredicate().isNone()) {
        return Optional.of(new ValuesNode(node.getId(), node.getOutputSymbols(), ImmutableList.of()));
    }
    TupleDomain<ColumnHandle> remainingFilter = result.get().getRemainingFilter();
    Optional<ConnectorExpression> remainingConnectorExpression = result.get().getRemainingExpression();
    boolean precalculateStatistics = result.get().isPrecalculateStatistics();
    verifyTablePartitioning(session, plannerContext.getMetadata(), node, newTablePartitioning);
    TableScanNode tableScan = new TableScanNode(node.getId(), newTable, node.getOutputSymbols(), node.getAssignments(), computeEnforced(newDomain, remainingFilter), // TODO (https://github.com/trinodb/trino/issues/8144) distinguish between predicate pushed down and remaining
    deriveTableStatisticsForPushdown(statsProvider, session, precalculateStatistics, filterNode), node.isUpdateTarget(), node.getUseConnectorNodePartitioning());
    Expression remainingDecomposedPredicate;
    if (remainingConnectorExpression.isEmpty() || remainingConnectorExpression.equals(connectorExpression)) {
        remainingDecomposedPredicate = decomposedPredicate.getRemainingExpression();
    } else {
        Map<String, Symbol> variableMappings = assignments.values().stream().collect(toImmutableMap(Symbol::getName, Function.identity()));
        Expression translatedExpression = ConnectorExpressionTranslator.translate(session, remainingConnectorExpression.get(), plannerContext, variableMappings, new LiteralEncoder(plannerContext));
        if (connectorExpression.isEmpty()) {
            remainingDecomposedPredicate = ExpressionUtils.combineConjuncts(plannerContext.getMetadata(), translatedExpression, decomposedPredicate.getRemainingExpression());
        } else {
            remainingDecomposedPredicate = translatedExpression;
        }
    }
    Expression resultingPredicate = createResultingPredicate(plannerContext, session, symbolAllocator, typeAnalyzer, splitExpression.getDynamicFilter(), domainTranslator.toPredicate(session, remainingFilter.transformKeys(assignments::get)), splitExpression.getNonDeterministicPredicate(), remainingDecomposedPredicate);
    if (!TRUE_LITERAL.equals(resultingPredicate)) {
        return Optional.of(new FilterNode(filterNode.getId(), tableScan, resultingPredicate));
    }
    return Optional.of(tableScan);
}
Also used : LayoutConstraintEvaluator(io.trino.sql.planner.LayoutConstraintEvaluator) SymbolAllocator(io.trino.sql.planner.SymbolAllocator) FilterNode(io.trino.sql.planner.plan.FilterNode) PlanNode(io.trino.sql.planner.plan.PlanNode) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) DeterminismEvaluator.isDeterministic(io.trino.sql.planner.DeterminismEvaluator.isDeterministic) Map(java.util.Map) TableScanNode(io.trino.sql.planner.plan.TableScanNode) Rules.deriveTableStatisticsForPushdown(io.trino.sql.planner.iterative.rule.Rules.deriveTableStatisticsForPushdown) TRUE(io.trino.spi.expression.Constant.TRUE) ImmutableMap(com.google.common.collect.ImmutableMap) Domain(io.trino.spi.predicate.Domain) ConnectorExpressionTranslator(io.trino.sql.planner.ConnectorExpressionTranslator) Patterns.tableScan(io.trino.sql.planner.plan.Patterns.tableScan) StatsProvider(io.trino.cost.StatsProvider) Objects(java.util.Objects) List(java.util.List) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) Pattern(io.trino.matching.Pattern) SystemSessionProperties.isAllowPushdownIntoConnectors(io.trino.SystemSessionProperties.isAllowPushdownIntoConnectors) Optional(java.util.Optional) Expression(io.trino.sql.tree.Expression) ExpressionUtils.extractConjuncts(io.trino.sql.ExpressionUtils.extractConjuncts) ValuesNode(io.trino.sql.planner.plan.ValuesNode) ExpressionUtils.combineConjuncts(io.trino.sql.ExpressionUtils.combineConjuncts) Session(io.trino.Session) PlannerContext(io.trino.sql.PlannerContext) Constraint(io.trino.spi.connector.Constraint) LiteralEncoder(io.trino.sql.planner.LiteralEncoder) Type(io.trino.spi.type.Type) Patterns.filter(io.trino.sql.planner.plan.Patterns.filter) TableProperties(io.trino.metadata.TableProperties) Function(java.util.function.Function) Capture.newCapture(io.trino.matching.Capture.newCapture) ArrayList(java.util.ArrayList) ImmutableBiMap(com.google.common.collect.ImmutableBiMap) ImmutableList(com.google.common.collect.ImmutableList) Verify.verify(com.google.common.base.Verify.verify) NodeRef(io.trino.sql.tree.NodeRef) Objects.requireNonNull(java.util.Objects.requireNonNull) ColumnHandle(io.trino.spi.connector.ColumnHandle) Rule(io.trino.sql.planner.iterative.Rule) DomainTranslator(io.trino.sql.planner.DomainTranslator) TablePartitioning(io.trino.metadata.TableProperties.TablePartitioning) ExpressionUtils(io.trino.sql.ExpressionUtils) Symbol(io.trino.sql.planner.Symbol) ConstraintApplicationResult(io.trino.spi.connector.ConstraintApplicationResult) TRUE_LITERAL(io.trino.sql.tree.BooleanLiteral.TRUE_LITERAL) TupleDomain(io.trino.spi.predicate.TupleDomain) Capture(io.trino.matching.Capture) TableHandle(io.trino.metadata.TableHandle) ConnectorExpression(io.trino.spi.expression.ConnectorExpression) TypeAnalyzer(io.trino.sql.planner.TypeAnalyzer) Patterns.source(io.trino.sql.planner.plan.Patterns.source) DynamicFilters.isDynamicFilter(io.trino.sql.DynamicFilters.isDynamicFilter) Captures(io.trino.matching.Captures) Metadata(io.trino.metadata.Metadata) ValuesNode(io.trino.sql.planner.plan.ValuesNode) Constraint(io.trino.spi.connector.Constraint) ConnectorExpression(io.trino.spi.expression.ConnectorExpression) Symbol(io.trino.sql.planner.Symbol) FilterNode(io.trino.sql.planner.plan.FilterNode) NodeRef(io.trino.sql.tree.NodeRef) TablePartitioning(io.trino.metadata.TableProperties.TablePartitioning) LiteralEncoder(io.trino.sql.planner.LiteralEncoder) DomainTranslator(io.trino.sql.planner.DomainTranslator) ConstraintApplicationResult(io.trino.spi.connector.ConstraintApplicationResult) ColumnHandle(io.trino.spi.connector.ColumnHandle) Type(io.trino.spi.type.Type) TableScanNode(io.trino.sql.planner.plan.TableScanNode) Expression(io.trino.sql.tree.Expression) ConnectorExpression(io.trino.spi.expression.ConnectorExpression) ConnectorExpressionTranslator(io.trino.sql.planner.ConnectorExpressionTranslator) TableHandle(io.trino.metadata.TableHandle) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) ImmutableBiMap(com.google.common.collect.ImmutableBiMap) TableProperties(io.trino.metadata.TableProperties) LayoutConstraintEvaluator(io.trino.sql.planner.LayoutConstraintEvaluator)

Example 3 with StatsProvider

use of io.trino.cost.StatsProvider in project trino by trinodb.

the class DistinctLimitMatcher 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());
    DistinctLimitNode distinctLimitNode = (DistinctLimitNode) node;
    if (distinctLimitNode.getLimit() != limit) {
        return NO_MATCH;
    }
    if (!distinctLimitNode.getHashSymbol().equals(hashSymbol.map(alias -> alias.toSymbol(symbolAliases)))) {
        return NO_MATCH;
    }
    return new MatchResult(ImmutableSet.copyOf(distinctLimitNode.getDistinctSymbols()).equals(distinctSymbols.stream().map(alias -> alias.toSymbol(symbolAliases)).collect(toImmutableSet())));
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) StatsProvider(io.trino.cost.StatsProvider) PlanNode(io.trino.sql.planner.plan.PlanNode) Preconditions.checkState(com.google.common.base.Preconditions.checkState) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) Objects.requireNonNull(java.util.Objects.requireNonNull) DistinctLimitNode(io.trino.sql.planner.plan.DistinctLimitNode) Metadata(io.trino.metadata.Metadata) Optional(java.util.Optional) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) NO_MATCH(io.trino.sql.planner.assertions.MatchResult.NO_MATCH) Session(io.trino.Session) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) DistinctLimitNode(io.trino.sql.planner.plan.DistinctLimitNode)

Example 4 with StatsProvider

use of io.trino.cost.StatsProvider in project trino by trinodb.

the class IndexJoinMatcher 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());
    IndexJoinNode indexJoinNode = (IndexJoinNode) node;
    if (indexJoinNode.getCriteria().size() != criteria.size()) {
        return NO_MATCH;
    }
    Set<IndexJoinNode.EquiJoinClause> actualCriteria = ImmutableSet.copyOf(indexJoinNode.getCriteria());
    Set<IndexJoinNode.EquiJoinClause> expectedCriteria = criteria.stream().map(equiClause -> equiClause.getExpectedValue(symbolAliases)).collect(toImmutableSet());
    if (!expectedCriteria.equals(actualCriteria)) {
        return NO_MATCH;
    }
    if (!indexJoinNode.getProbeHashSymbol().equals(probeHashSymbol.map(alias -> alias.toSymbol(symbolAliases)))) {
        return NO_MATCH;
    }
    if (!indexJoinNode.getIndexHashSymbol().equals(indexHashSymbol.map(alias -> alias.toSymbol(symbolAliases)))) {
        return NO_MATCH;
    }
    return MatchResult.match();
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) IndexJoinNode(io.trino.sql.planner.plan.IndexJoinNode) Set(java.util.Set) StatsProvider(io.trino.cost.StatsProvider) PlanNode(io.trino.sql.planner.plan.PlanNode) Preconditions.checkState(com.google.common.base.Preconditions.checkState) List(java.util.List) Objects.requireNonNull(java.util.Objects.requireNonNull) Metadata(io.trino.metadata.Metadata) Optional(java.util.Optional) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) NO_MATCH(io.trino.sql.planner.assertions.MatchResult.NO_MATCH) Session(io.trino.Session) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) IndexJoinNode(io.trino.sql.planner.plan.IndexJoinNode)

Example 5 with StatsProvider

use of io.trino.cost.StatsProvider in project trino by trinodb.

the class UnnestMatcher 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());
    UnnestNode unnestNode = (UnnestNode) node;
    if (unnestNode.getReplicateSymbols().size() != replicateSymbols.size()) {
        return NO_MATCH;
    }
    if (!replicateSymbols.stream().map(symbolAliases::get).map(Symbol::from).collect(toImmutableList()).equals(unnestNode.getReplicateSymbols())) {
        return NO_MATCH;
    }
    if (unnestNode.getMappings().size() != unnestMappings.size()) {
        return NO_MATCH;
    }
    if (!IntStream.range(0, unnestMappings.size()).boxed().allMatch(index -> {
        Mapping nodeMapping = unnestNode.getMappings().get(index);
        PlanMatchPattern.UnnestMapping patternMapping = unnestMappings.get(index);
        return nodeMapping.getInput().toSymbolReference().equals(symbolAliases.get(patternMapping.getInput())) && patternMapping.getOutputs().size() == nodeMapping.getOutputs().size();
    })) {
        return NO_MATCH;
    }
    if (ordinalitySymbol.isPresent() != unnestNode.getOrdinalitySymbol().isPresent()) {
        return NO_MATCH;
    }
    if (!type.equals(unnestNode.getJoinType())) {
        return NO_MATCH;
    }
    if (filter.isPresent() != unnestNode.getFilter().isPresent()) {
        return NO_MATCH;
    }
    if (filter.isEmpty()) {
        return MatchResult.match();
    }
    if (!new ExpressionVerifier(symbolAliases).process(unnestNode.getFilter().get(), filter.get())) {
        return NO_MATCH;
    }
    return MatchResult.match();
}
Also used : IntStream(java.util.stream.IntStream) Symbol(io.trino.sql.planner.Symbol) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) StatsProvider(io.trino.cost.StatsProvider) UnnestNode(io.trino.sql.planner.plan.UnnestNode) PlanNode(io.trino.sql.planner.plan.PlanNode) Preconditions.checkState(com.google.common.base.Preconditions.checkState) List(java.util.List) Mapping(io.trino.sql.planner.plan.UnnestNode.Mapping) Objects.requireNonNull(java.util.Objects.requireNonNull) Metadata(io.trino.metadata.Metadata) Optional(java.util.Optional) NO_MATCH(io.trino.sql.planner.assertions.MatchResult.NO_MATCH) Expression(io.trino.sql.tree.Expression) JoinNode(io.trino.sql.planner.plan.JoinNode) Session(io.trino.Session) MoreObjects.toStringHelper(com.google.common.base.MoreObjects.toStringHelper) UnnestNode(io.trino.sql.planner.plan.UnnestNode) Mapping(io.trino.sql.planner.plan.UnnestNode.Mapping)

Aggregations

StatsProvider (io.trino.cost.StatsProvider)21 PlanNode (io.trino.sql.planner.plan.PlanNode)15 Session (io.trino.Session)14 Metadata (io.trino.metadata.Metadata)14 List (java.util.List)14 MoreObjects.toStringHelper (com.google.common.base.MoreObjects.toStringHelper)13 Preconditions.checkState (com.google.common.base.Preconditions.checkState)13 NO_MATCH (io.trino.sql.planner.assertions.MatchResult.NO_MATCH)13 Optional (java.util.Optional)12 Objects.requireNonNull (java.util.Objects.requireNonNull)11 MatchResult.match (io.trino.sql.planner.assertions.MatchResult.match)9 Symbol (io.trino.sql.planner.Symbol)8 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)7 ImmutableSet.toImmutableSet (com.google.common.collect.ImmutableSet.toImmutableSet)6 CachingStatsProvider (io.trino.cost.CachingStatsProvider)5 Map (java.util.Map)5 Set (java.util.Set)5 ImmutableSet (com.google.common.collect.ImmutableSet)4 CachingCostProvider (io.trino.cost.CachingCostProvider)4 CostProvider (io.trino.cost.CostProvider)4