@Provides @Singleton public static StatsCalculator createNewStatsCalculator(Metadata metadata) { StatsNormalizer normalizer = new StatsNormalizer(); ScalarStatsCalculator scalarStatsCalculator = new ScalarStatsCalculator(metadata); FilterStatsCalculator filterStatsCalculator = new FilterStatsCalculator(metadata, scalarStatsCalculator, normalizer); ImmutableList.Builder<ComposableStatsCalculator.Rule<?>> rules = ImmutableList.builder(); rules.add(new OutputStatsRule()); rules.add(new TableScanStatsRule(metadata, normalizer)); rules.add(new SimpleFilterProjectSemiJoinStatsRule(normalizer, filterStatsCalculator)); // this must be before FilterStatsRule rules.add(new FilterStatsRule(normalizer, filterStatsCalculator)); rules.add(new ValuesStatsRule(metadata)); rules.add(new LimitStatsRule(normalizer)); rules.add(new EnforceSingleRowStatsRule(normalizer)); rules.add(new ProjectStatsRule(scalarStatsCalculator, normalizer)); rules.add(new ExchangeStatsRule(normalizer)); rules.add(new JoinStatsRule(filterStatsCalculator, normalizer)); rules.add(new SpatialJoinStatsRule(filterStatsCalculator, normalizer)); rules.add(new AggregationStatsRule(normalizer)); rules.add(new UnionStatsRule(normalizer)); rules.add(new AssignUniqueIdStatsRule()); rules.add(new SemiJoinStatsRule()); rules.add(new RowNumberStatsRule(normalizer)); return new ComposableStatsCalculator(rules.build()); } }
private PlanNodeStatsAssertion assertExpression(Expression expression) { return PlanNodeStatsAssertion.assertThat(statsCalculator.filterStats( standardInputStatistics, expression, session, standardTypes)); } }
private Expression simplifyExpression(Session session, Expression predicate, TypeProvider types) { // TODO reuse com.facebook.presto.sql.planner.iterative.rule.SimplifyExpressions.rewrite Map<NodeRef<Expression>, Type> expressionTypes = getExpressionTypes(session, predicate, types); ExpressionInterpreter interpreter = ExpressionInterpreter.expressionOptimizer(predicate, metadata, session, expressionTypes); Object value = interpreter.optimize(NoOpSymbolResolver.INSTANCE); if (value == null) { // Expression evaluates to SQL null, which in Filter is equivalent to false. This assumes the expression is a top-level expression (eg. not in NOT). value = false; } return literalEncoder.toExpression(value, BOOLEAN); }
public PlanNodeStatsEstimate filterStats( PlanNodeStatsEstimate statsEstimate, Expression predicate, Session session, TypeProvider types) { Expression simplifiedExpression = simplifyExpression(session, predicate, types); return new FilterExpressionStatsCalculatingVisitor(statsEstimate, session, types) .process(simplifiedExpression); }
private PlanNodeStatsAssertion assertCalculate(Expression comparisonExpression) { return PlanNodeStatsAssertion.assertThat(filterStatsCalculator.filterStats(standardInputStatistics, comparisonExpression, session, types)); }
statsCalculator = new FilterStatsCalculator(metadata, new ScalarStatsCalculator(metadata), new StatsNormalizer());
private PlanNodeStatsEstimate computeInnerJoinStats(JoinNode node, PlanNodeStatsEstimate crossJoinStats, Session session, TypeProvider types) { List<EquiJoinClause> equiJoinCriteria = node.getCriteria(); if (equiJoinCriteria.isEmpty()) { if (!node.getFilter().isPresent()) { return crossJoinStats; } // TODO: this might explode stats return filterStatsCalculator.filterStats(crossJoinStats, node.getFilter().get(), session, types); } PlanNodeStatsEstimate equiJoinEstimate = filterByEquiJoinClauses(crossJoinStats, node.getCriteria(), session, types); if (equiJoinEstimate.isOutputRowCountUnknown()) { return PlanNodeStatsEstimate.unknown(); } if (!node.getFilter().isPresent()) { return equiJoinEstimate; } PlanNodeStatsEstimate filteredEquiJoinEstimate = filterStatsCalculator.filterStats(equiJoinEstimate, node.getFilter().get(), session, types); if (filteredEquiJoinEstimate.isOutputRowCountUnknown()) { return normalizer.normalize(equiJoinEstimate.mapOutputRowCount(rowCount -> rowCount * UNKNOWN_FILTER_COEFFICIENT), types); } return filteredEquiJoinEstimate; }
filterStatsCalculator = new FilterStatsCalculator(metadata, new ScalarStatsCalculator(metadata), new StatsNormalizer());
@Override protected Optional<PlanNodeStatsEstimate> doCalculate(SpatialJoinNode node, StatsProvider sourceStats, Lookup lookup, Session session, TypeProvider types) { PlanNodeStatsEstimate leftStats = sourceStats.getStats(node.getLeft()); PlanNodeStatsEstimate rightStats = sourceStats.getStats(node.getRight()); PlanNodeStatsEstimate crossJoinStats = crossJoinStats(node, leftStats, rightStats); switch (node.getType()) { case INNER: return Optional.of(statsCalculator.filterStats(crossJoinStats, node.getFilter(), session, types)); case LEFT: return Optional.of(PlanNodeStatsEstimate.unknown()); default: throw new IllegalArgumentException("Unknown spatial join type: " + node.getType()); } }
@Override public Optional<PlanNodeStatsEstimate> doCalculate(FilterNode node, StatsProvider statsProvider, Lookup lookup, Session session, TypeProvider types) { PlanNodeStatsEstimate sourceStats = statsProvider.getStats(node.getSource()); PlanNodeStatsEstimate estimate = filterStatsCalculator.filterStats(sourceStats, node.getPredicate(), session, types); if (isDefaultFilterFactorEnabled(session) && estimate.isOutputRowCountUnknown()) { estimate = sourceStats.mapOutputRowCount(sourceRowCount -> sourceStats.getOutputRowCount() * UNKNOWN_FILTER_COEFFICIENT); } return Optional.of(estimate); } }
private PlanNodeStatsEstimate filterByEquiJoinClauses( PlanNodeStatsEstimate stats, EquiJoinClause drivingClause, Collection<EquiJoinClause> remainingClauses, Session session, TypeProvider types) { ComparisonExpression drivingPredicate = new ComparisonExpression(EQUAL, drivingClause.getLeft().toSymbolReference(), drivingClause.getRight().toSymbolReference()); PlanNodeStatsEstimate filteredStats = filterStatsCalculator.filterStats(stats, drivingPredicate, session, types); for (EquiJoinClause clause : remainingClauses) { filteredStats = filterByAuxiliaryClause(filteredStats, clause, types); } return filteredStats; }
private Optional<PlanNodeStatsEstimate> calculate(FilterNode filterNode, SemiJoinNode semiJoinNode, StatsProvider statsProvider, Session session, TypeProvider types) { PlanNodeStatsEstimate sourceStats = statsProvider.getStats(semiJoinNode.getSource()); PlanNodeStatsEstimate filteringSourceStats = statsProvider.getStats(semiJoinNode.getFilteringSource()); Symbol filteringSourceJoinSymbol = semiJoinNode.getFilteringSourceJoinSymbol(); Symbol sourceJoinSymbol = semiJoinNode.getSourceJoinSymbol(); Optional<SemiJoinOutputFilter> semiJoinOutputFilter = extractSemiJoinOutputFilter(filterNode.getPredicate(), semiJoinNode.getSemiJoinOutput()); if (!semiJoinOutputFilter.isPresent()) { return Optional.empty(); } PlanNodeStatsEstimate semiJoinStats; if (semiJoinOutputFilter.get().isNegated()) { semiJoinStats = computeAntiJoin(sourceStats, filteringSourceStats, sourceJoinSymbol, filteringSourceJoinSymbol); } else { semiJoinStats = computeSemiJoin(sourceStats, filteringSourceStats, sourceJoinSymbol, filteringSourceJoinSymbol); } if (semiJoinStats.isOutputRowCountUnknown()) { return Optional.of(PlanNodeStatsEstimate.unknown()); } // apply remaining predicate PlanNodeStatsEstimate filteredStats = filterStatsCalculator.filterStats(semiJoinStats, semiJoinOutputFilter.get().getRemainingPredicate(), session, types); if (filteredStats.isOutputRowCountUnknown()) { return Optional.of(semiJoinStats.mapOutputRowCount(rowCount -> rowCount * UNKNOWN_FILTER_COEFFICIENT)); } return Optional.of(filteredStats); }