use of io.crate.planner.PositionalOrderBy in project crate by crate.
the class NestedLoopJoin method build.
@Override
public ExecutionPlan build(PlannerContext plannerContext, Set<PlanHint> hints, ProjectionBuilder projectionBuilder, int limit, int offset, @Nullable OrderBy order, @Nullable Integer pageSizeHint, Row params, SubQueryResults subQueryResults) {
/*
* Benchmarks reveal that if rows are filtered out distributed execution gives better performance.
* Therefore if `filterNeeded` is true (there is joinCondition or a filtering after the join operation)
* then it's a good indication that distributed execution will be faster.
*
* We may at some point add some kind of session-settings to override this behaviour
* or otherwise come up with a better heuristic.
*/
Integer childPageSizeHint = !isFiltered && limit != TopN.NO_LIMIT ? limitAndOffset(limit, offset) : null;
ExecutionPlan left = lhs.build(plannerContext, hints, projectionBuilder, NO_LIMIT, 0, null, childPageSizeHint, params, subQueryResults);
ExecutionPlan right = rhs.build(plannerContext, hints, projectionBuilder, NO_LIMIT, 0, null, childPageSizeHint, params, subQueryResults);
PositionalOrderBy orderByFromLeft = left.resultDescription().orderBy();
boolean hasDocTables = baseTables.stream().anyMatch(r -> r instanceof DocTableRelation);
boolean isDistributed = hasDocTables && isFiltered && !joinType.isOuter();
LogicalPlan leftLogicalPlan = lhs;
LogicalPlan rightLogicalPlan = rhs;
isDistributed = isDistributed && (!left.resultDescription().nodeIds().isEmpty() && !right.resultDescription().nodeIds().isEmpty());
boolean blockNlPossible = !isDistributed && isBlockNlPossible(left, right);
JoinType joinType = this.joinType;
if (!orderByWasPushedDown && joinType.supportsInversion() && (isDistributed && lhs.numExpectedRows() < rhs.numExpectedRows() && orderByFromLeft == null) || (blockNlPossible && lhs.numExpectedRows() > rhs.numExpectedRows())) {
// 1) The right side is always broadcast-ed, so for performance reasons we switch the tables so that
// the right table is the smaller (numOfRows). If left relation has a pushed-down OrderBy that needs
// to be preserved, then the switch is not possible.
// 2) For block nested loop, the left side should always be smaller. Benchmarks have shown that the
// performance decreases if the left side is much larger and no limit is applied.
ExecutionPlan tmpExecutionPlan = left;
left = right;
right = tmpExecutionPlan;
leftLogicalPlan = rhs;
rightLogicalPlan = lhs;
joinType = joinType.invert();
}
Tuple<Collection<String>, List<MergePhase>> joinExecutionNodesAndMergePhases = configureExecution(left, right, plannerContext, isDistributed);
List<Symbol> joinOutputs = Lists2.concat(leftLogicalPlan.outputs(), rightLogicalPlan.outputs());
SubQueryAndParamBinder paramBinder = new SubQueryAndParamBinder(params, subQueryResults);
Symbol joinInput = null;
if (joinCondition != null) {
joinInput = InputColumns.create(paramBinder.apply(joinCondition), joinOutputs);
}
NestedLoopPhase nlPhase = new NestedLoopPhase(plannerContext.jobId(), plannerContext.nextExecutionPhaseId(), isDistributed ? "distributed-nested-loop" : "nested-loop", Collections.singletonList(JoinOperations.createJoinProjection(outputs, joinOutputs)), joinExecutionNodesAndMergePhases.v2().get(0), joinExecutionNodesAndMergePhases.v2().get(1), leftLogicalPlan.outputs().size(), rightLogicalPlan.outputs().size(), joinExecutionNodesAndMergePhases.v1(), joinType, joinInput, Symbols.typeView(leftLogicalPlan.outputs()), leftLogicalPlan.estimatedRowSize(), leftLogicalPlan.numExpectedRows(), blockNlPossible);
return new Join(nlPhase, left, right, TopN.NO_LIMIT, 0, TopN.NO_LIMIT, outputs.size(), orderByFromLeft);
}
use of io.crate.planner.PositionalOrderBy in project crate by crate.
the class GroupByPlannerTest method testNonDistributedGroupByOnClusteredColumnSortedScalar.
@Test
public void testNonDistributedGroupByOnClusteredColumnSortedScalar() throws Exception {
var e = SQLExecutor.builder(clusterService, 2, RandomizedTest.getRandom(), List.of()).addTable(TableDefinitions.USER_TABLE_DEFINITION).build();
Merge merge = e.plan("select count(*) + 1, id from users group by id order by count(*) + 1 limit 20");
Collect collect = (Collect) merge.subPlan();
RoutedCollectPhase collectPhase = ((RoutedCollectPhase) collect.collectPhase());
assertThat(collectPhase.projections(), contains(instanceOf(GroupProjection.class), instanceOf(OrderedTopNProjection.class), instanceOf(EvalProjection.class)));
assertThat(((OrderedTopNProjection) collectPhase.projections().get(1)).orderBy().size(), is(1));
assertThat(collectPhase.projections().get(0).requiredGranularity(), is(RowGranularity.SHARD));
MergePhase mergePhase = merge.mergePhase();
assertThat(mergePhase.projections(), contains(instanceOf(TopNProjection.class)));
PositionalOrderBy positionalOrderBy = mergePhase.orderByPositions();
assertThat(positionalOrderBy, notNullValue());
assertThat(positionalOrderBy.indices().length, is(1));
assertThat(positionalOrderBy.indices()[0], is(0));
assertThat(positionalOrderBy.reverseFlags()[0], is(false));
assertThat(positionalOrderBy.nullsFirst()[0], is(false));
}
use of io.crate.planner.PositionalOrderBy in project crate by crate.
the class GroupByPlannerTest method testNonDistributedGroupByOnClusteredColumnSorted.
@Test
public void testNonDistributedGroupByOnClusteredColumnSorted() throws Exception {
var e = SQLExecutor.builder(clusterService, 2, RandomizedTest.getRandom(), List.of()).addTable(TableDefinitions.USER_TABLE_DEFINITION).build();
Merge merge = e.plan("select count(*), id from users group by id order by 1 desc nulls last limit 20");
Collect collect = ((Collect) merge.subPlan());
RoutedCollectPhase collectPhase = ((RoutedCollectPhase) collect.collectPhase());
List<Projection> collectProjections = collectPhase.projections();
assertThat(collectProjections, contains(instanceOf(GroupProjection.class), instanceOf(OrderedTopNProjection.class), // swap id, count(*) -> count(*), id
instanceOf(EvalProjection.class)));
assertThat(collectProjections.get(1), instanceOf(OrderedTopNProjection.class));
assertThat(((OrderedTopNProjection) collectProjections.get(1)).orderBy().size(), is(1));
assertThat(collectProjections.get(0).requiredGranularity(), is(RowGranularity.SHARD));
MergePhase mergePhase = merge.mergePhase();
assertThat(mergePhase.projections(), contains(instanceOf(TopNProjection.class)));
PositionalOrderBy positionalOrderBy = mergePhase.orderByPositions();
assertThat(positionalOrderBy, notNullValue());
assertThat(positionalOrderBy.indices().length, is(1));
assertThat(positionalOrderBy.indices()[0], is(0));
assertThat(positionalOrderBy.reverseFlags()[0], is(true));
assertThat(positionalOrderBy.nullsFirst()[0], is(false));
}
use of io.crate.planner.PositionalOrderBy in project crate by crate.
the class Eval method addEvalProjection.
private ExecutionPlan addEvalProjection(PlannerContext plannerContext, ExecutionPlan executionPlan, Row params, SubQueryResults subQueryResults) {
PositionalOrderBy orderBy = executionPlan.resultDescription().orderBy();
PositionalOrderBy newOrderBy = null;
SubQueryAndParamBinder binder = new SubQueryAndParamBinder(params, subQueryResults);
List<Symbol> boundOutputs = Lists2.map(outputs, binder);
if (orderBy != null) {
newOrderBy = orderBy.tryMapToNewOutputs(source.outputs(), boundOutputs);
if (newOrderBy == null) {
executionPlan = Merge.ensureOnHandler(executionPlan, plannerContext);
}
}
InputColumns.SourceSymbols ctx = new InputColumns.SourceSymbols(Lists2.map(source.outputs(), binder));
executionPlan.addProjection(new EvalProjection(InputColumns.create(boundOutputs, ctx)), executionPlan.resultDescription().limit(), executionPlan.resultDescription().offset(), newOrderBy);
return executionPlan;
}
use of io.crate.planner.PositionalOrderBy in project crate by crate.
the class Order method build.
@Override
public ExecutionPlan build(PlannerContext plannerContext, Set<PlanHint> planHints, ProjectionBuilder projectionBuilder, int limit, int offset, @Nullable OrderBy order, @Nullable Integer pageSizeHint, Row params, SubQueryResults subQueryResults) {
ExecutionPlan plan = source.build(plannerContext, planHints, projectionBuilder, limit, offset, orderBy, pageSizeHint, params, subQueryResults);
if (plan.resultDescription().orderBy() != null) {
// Collect applied ORDER BY eagerly to produce a optimized execution plan;
if (source instanceof Collect) {
return plan;
}
}
if (plan.resultDescription().hasRemainingLimitOrOffset()) {
plan = Merge.ensureOnHandler(plan, plannerContext);
}
InputColumns.SourceSymbols ctx = new InputColumns.SourceSymbols(source.outputs());
List<Symbol> orderByInputColumns = InputColumns.create(this.orderBy.orderBySymbols(), ctx);
ensureOrderByColumnsArePresentInOutputs(orderByInputColumns);
OrderedTopNProjection topNProjection = new OrderedTopNProjection(Limit.limitAndOffset(limit, offset), 0, InputColumns.create(outputs, ctx), orderByInputColumns, this.orderBy.reverseFlags(), this.orderBy.nullsFirst());
PositionalOrderBy positionalOrderBy = PositionalOrderBy.of(this.orderBy, outputs);
plan.addProjection(topNProjection, limit, offset, positionalOrderBy);
return plan;
}
Aggregations