Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public NereidsPlanner(StatementContext statementContext) {

@Override
public void plan(StatementBase queryStmt, org.apache.doris.thrift.TQueryOptions queryOptions) {
this.queryOptions = queryOptions;
if (statementContext.getConnectContext().getSessionVariable().isEnableNereidsTrace()) {
NereidsTracer.init();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.OriginStatement;
import org.apache.doris.qe.SessionVariable;
import org.apache.doris.qe.ShortCircuitQueryContext;
import org.apache.doris.qe.cache.CacheAnalyzer;
import org.apache.doris.statistics.Statistics;

Expand Down Expand Up @@ -122,8 +123,8 @@ public class StatementContext implements Closeable {

// generate for next id for prepared statement's placeholders, which is connection level
private final IdGenerator<PlaceholderId> placeHolderIdGenerator = PlaceholderId.createGenerator();
// relation id to placeholders for prepared statement
private final Map<PlaceholderId, Expression> idToPlaceholderRealExpr = new HashMap<>();
// relation id to placeholders for prepared statement, ordered by placeholder id
private final Map<PlaceholderId, Expression> idToPlaceholderRealExpr = new TreeMap<>();

// collect all hash join conditions to compute node connectivity in join graph
private final List<Expression> joinFilters = new ArrayList<>();
Expand Down Expand Up @@ -164,6 +165,12 @@ public class StatementContext implements Closeable {
// form this map
private final Map<RelationId, Statistics> relationIdToStatisticsMap = new LinkedHashMap<>();

// Indicates the query is short-circuited in both plan and execution phase, typically
// for high speed/concurrency point queries
private boolean isShortCircuitQuery;

private ShortCircuitQueryContext shortCircuitQueryContext;

public StatementContext() {
this(ConnectContext.get(), null, 0);
}
Expand Down Expand Up @@ -235,6 +242,22 @@ public void setMaxContinuousJoin(int joinCount) {
}
}

public boolean isShortCircuitQuery() {
return isShortCircuitQuery;
}

public void setShortCircuitQuery(boolean shortCircuitQuery) {
isShortCircuitQuery = shortCircuitQuery;
}

public ShortCircuitQueryContext getShortCircuitQueryContext() {
return shortCircuitQueryContext;
}

public void setShortCircuitQueryContext(ShortCircuitQueryContext shortCircuitQueryContext) {
this.shortCircuitQueryContext = shortCircuitQueryContext;
}

public Optional<SqlCacheContext> getSqlCacheContext() {
return Optional.ofNullable(sqlCacheContext);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import org.apache.doris.nereids.rules.rewrite.InferSetOperatorDistinct;
import org.apache.doris.nereids.rules.rewrite.InlineLogicalView;
import org.apache.doris.nereids.rules.rewrite.LimitSortToTopN;
import org.apache.doris.nereids.rules.rewrite.LogicalResultSinkToShortCircuitPointQuery;
import org.apache.doris.nereids.rules.rewrite.MergeAggregate;
import org.apache.doris.nereids.rules.rewrite.MergeFilters;
import org.apache.doris.nereids.rules.rewrite.MergeOneRowRelationIntoUnion;
Expand Down Expand Up @@ -398,6 +399,8 @@ public class Rewriter extends AbstractBatchJobExecutor {
topic("topn optimize",
topDown(new DeferMaterializeTopNResult())
),
topic("Point query short circuit",
topDown(new LogicalResultSinkToShortCircuitPointQuery())),
topic("eliminate",
// SORT_PRUNING should be applied after mergeLimit
custom(RuleType.ELIMINATE_SORT, EliminateSort::new),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ public enum RuleType {
BUILD_AGG_FOR_RANDOM_DISTRIBUTED_TABLE_PROJECT_SCAN(RuleTypeClass.REWRITE),
BUILD_AGG_FOR_RANDOM_DISTRIBUTED_TABLE_FILTER_SCAN(RuleTypeClass.REWRITE),
BUILD_AGG_FOR_RANDOM_DISTRIBUTED_TABLE_AGG_SCAN(RuleTypeClass.REWRITE),
// short circuit rule
SHOR_CIRCUIT_POINT_QUERY(RuleTypeClass.REWRITE),
// exploration rules
REORDER_INTERSECT(RuleTypeClass.EXPLORATION),
TEST_EXPLORATION(RuleTypeClass.EXPLORATION),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package org.apache.doris.nereids.rules.rewrite;

import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.OlapTable;
import org.apache.doris.nereids.StatementContext;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.expressions.Cast;
import org.apache.doris.nereids.trees.expressions.EqualTo;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
import org.apache.doris.qe.ConnectContext;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;

import java.util.List;
import java.util.Set;

/**
* short circuit query optimization
* pattern : select xxx from tbl where key = ?
*/
public class LogicalResultSinkToShortCircuitPointQuery implements RewriteRuleFactory {

private Expression removeCast(Expression expression) {
if (expression instanceof Cast) {
return expression.child(0);
}
return expression;
}

private boolean filterMatchShortCircuitCondition(LogicalFilter<LogicalOlapScan> filter) {
return filter.getConjuncts().stream().allMatch(
// all conjuncts match with pattern `key = ?`
expression -> (expression instanceof EqualTo)
&& (removeCast(expression.child(0)).isKeyColumnFromTable()
|| ((SlotReference) expression.child(0)).getName().equals(Column.DELETE_SIGN))
&& expression.child(1).isLiteral());
}

private boolean scanMatchShortCircuitCondition(LogicalOlapScan olapScan) {
if (!ConnectContext.get().getSessionVariable().enableShortCircuitQuery) {
return false;
}
OlapTable olapTable = olapScan.getTable();
return olapTable.getEnableLightSchemaChange() && olapTable.getEnableUniqueKeyMergeOnWrite()
&& olapTable.storeRowColumn();
}

// set short circuit flag and return the original plan
private Plan shortCircuit(Plan root, OlapTable olapTable,
Set<Expression> conjuncts, StatementContext statementContext) {
// All key columns in conjuncts
Set<String> colNames = Sets.newHashSet();
for (Expression expr : conjuncts) {
colNames.add(((SlotReference) removeCast((expr.child(0)))).getName());
}
// set short circuit flag and modify nothing to the plan
if (olapTable.getBaseSchemaKeyColumns().size() <= colNames.size()) {
statementContext.setShortCircuitQuery(true);
}
return root;
}

@Override
public List<Rule> buildRules() {
return ImmutableList.of(
RuleType.SHOR_CIRCUIT_POINT_QUERY.build(
logicalResultSink(logicalProject(logicalFilter(logicalOlapScan()
.when(this::scanMatchShortCircuitCondition)
).when(this::filterMatchShortCircuitCondition)))
.thenApply(ctx -> {
return shortCircuit(ctx.root, ctx.root.child().child().child().getTable(),

ctx.root.child().child().getConjuncts(), ctx.statementContext);
})),
RuleType.SHOR_CIRCUIT_POINT_QUERY.build(
logicalResultSink(logicalFilter(logicalOlapScan()
.when(this::scanMatchShortCircuitCondition)
).when(this::filterMatchShortCircuitCondition))
.thenApply(ctx -> {
return shortCircuit(ctx.root, ctx.root.child().child().getTable(),
ctx.root.child().getConjuncts(), ctx.statementContext);
}))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,11 @@ public boolean isColumnFromTable() {
return (this instanceof SlotReference) && ((SlotReference) this).getColumn().isPresent();
}

public boolean isKeyColumnFromTable() {
return (this instanceof SlotReference) && ((SlotReference) this).getColumn().isPresent()
&& ((SlotReference) this).getColumn().get().isKey();
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ private static Literal handleDateTimeLiteral(ByteBuffer data) {
microsecond = data.getInt();
}
if (Config.enable_date_conversion) {
return new DateTimeV2Literal(year, month, day, hour, minute, second, microsecond);
return new DateTimeV2Literal(DateTimeV2Type.MAX, year, month, day, hour, minute, second, microsecond);
}
return new DateTimeLiteral(DateTimeType.INSTANCE, year, month, day, hour, minute, second, microsecond);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
/**
* placeholder id for prepared statement parameters
*/
public class PlaceholderId extends Id<PlaceholderId> {
public class PlaceholderId extends Id<PlaceholderId> implements Comparable<PlaceholderId> {

public PlaceholderId(int id) {
super(id);
Expand Down Expand Up @@ -55,4 +55,9 @@ public boolean equals(Object obj) {
public int hashCode() {
return super.hashCode();
}

@Override
public int compareTo(PlaceholderId o) {
return this.id - o.id;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@

package org.apache.doris.nereids.trees.plans.commands;

import org.apache.doris.analysis.Queriable;
import org.apache.doris.nereids.StatementContext;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.glue.LogicalPlanAdapter;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.PointQueryExecutor;
import org.apache.doris.qe.PreparedStatementContext;
import org.apache.doris.qe.ShortCircuitQueryContext;
import org.apache.doris.qe.StmtExecutor;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -65,8 +69,26 @@ public void run(ConnectContext ctx, StmtExecutor executor) throws Exception {
LogicalPlanAdapter planAdapter = new LogicalPlanAdapter(prepareCommand.getLogicalPlan(), executor.getContext()
.getStatementContext());
executor.setParsedStmt(planAdapter);
// execute real statement
executor.execute();
// If it's not a short circuit query or schema version is different(indicates schema changed),
// need to do reanalyze and plan
boolean needAnalyze = !executor.getContext().getStatementContext().isShortCircuitQuery()
|| (preparedStmtCtx.shortCircuitQueryContext.isPresent()
&& preparedStmtCtx.shortCircuitQueryContext.get().tbl.getBaseSchemaVersion()
!= preparedStmtCtx.shortCircuitQueryContext.get().schemaVersion);
if (needAnalyze) {
// execute real statement
preparedStmtCtx.shortCircuitQueryContext = Optional.empty();
statementContext.setShortCircuitQueryContext(null);
executor.execute();
if (executor.getContext().getStatementContext().isShortCircuitQuery()) {
// cache short-circuit plan
preparedStmtCtx.shortCircuitQueryContext = Optional.of(
new ShortCircuitQueryContext(executor.planner(), (Queriable) executor.getParsedStmt()));
statementContext.setShortCircuitQueryContext(preparedStmtCtx.shortCircuitQueryContext.get());
}
return;
}
PointQueryExecutor.directExecuteShortCircuitQuery(executor, preparedStmtCtx, statementContext);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,8 @@ public Map<SlotRef, Expr> getPointQueryEqualPredicates() {

public boolean isPointQuery() {
return this.pointQueryEqualPredicats != null
|| (preparedStatment != null && preparedStatment.isPointQueryShortCircuit());
|| (preparedStatment != null && preparedStatment.isPointQueryShortCircuit())
|| ConnectContext.get().getStatementContext().isShortCircuitQuery();
}

private void computeTabletInfo() throws UserException {
Expand Down Expand Up @@ -1250,6 +1251,7 @@ public List<TScanRangeLocations> lazyEvaluateRangeLocations() throws UserExcepti
scanTabletIds.clear();
bucketSeq2locations.clear();
scanReplicaIds.clear();
sampleTabletIds.clear();
try {
createScanRangeLocations();
} catch (AnalysisException e) {
Expand Down Expand Up @@ -1350,7 +1352,7 @@ public String getNodeExplainString(String prefix, TExplainLevel detailLevel) {
output.append(prefix).append("pushAggOp=").append(pushDownAggNoGroupingOp).append("\n");
}
if (isPointQuery()) {
output.append(prefix).append("SHORT-CIRCUIT");
output.append(prefix).append("SHORT-CIRCUIT\n");
}

if (!CollectionUtils.isEmpty(rewrittenProjectList)) {
Expand Down
Loading