use of com.facebook.presto.sql.planner.plan.ExchangeNode.Scope.LOCAL in project presto by prestodb.
the class TestValidateAggregationsWithDefaultValues method testWithPartialAggregationBelowJoin.
@Test
public void testWithPartialAggregationBelowJoin() {
PlanNode root = builder.aggregation(af -> af.step(FINAL).groupingSets(groupingSets(ImmutableList.of(variable), 2, ImmutableSet.of(0))).source(builder.join(INNER, builder.exchange(e -> e.type(REPARTITION).scope(LOCAL).fixedHashDistributionParitioningScheme(ImmutableList.of(variable), ImmutableList.of(variable)).addInputsSet(variable).addSource(builder.aggregation(ap -> ap.step(PARTIAL).groupingSets(groupingSets(ImmutableList.of(variable), 2, ImmutableSet.of(0))).source(tableScanNode)))), builder.values())));
validatePlan(root, true);
}
use of com.facebook.presto.sql.planner.plan.ExchangeNode.Scope.LOCAL 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);
}
use of com.facebook.presto.sql.planner.plan.ExchangeNode.Scope.LOCAL in project presto by prestodb.
the class TestValidateAggregationsWithDefaultValues method testWithPartialAggregationBelowJoinWithoutSeparatingExchange.
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Final aggregation with default value not separated from partial aggregation by local hash exchange")
public void testWithPartialAggregationBelowJoinWithoutSeparatingExchange() {
PlanNode root = builder.aggregation(af -> af.step(FINAL).groupingSets(groupingSets(ImmutableList.of(variable), 2, ImmutableSet.of(0))).source(builder.join(INNER, builder.aggregation(ap -> ap.step(PARTIAL).groupingSets(groupingSets(ImmutableList.of(variable), 2, ImmutableSet.of(0))).source(tableScanNode)), builder.values())));
validatePlan(root, true);
}
Aggregations