This is an automated email from the ASF dual-hosted git repository.
caogaofei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 69715dff132 Fix optimizers doesn't work when execute Explain Analyze
query
69715dff132 is described below
commit 69715dff1327c3616ac71cec6778d78e3b2395c1
Author: Weihao Li <[email protected]>
AuthorDate: Fri Mar 21 17:48:51 2025 +0800
Fix optimizers doesn't work when execute Explain Analyze query
---
.../plan/planner/plan/node/PlanGraphPrinter.java | 9 ++++
.../relational/planner/TableLogicalPlanner.java | 13 +++++-
.../iterative/rule/PruneExplainAnalyzeColumns.java | 49 ++++++++++++++++++++++
.../planner/node/ExplainAnalyzeNode.java | 20 +++++++--
.../plan/relational/planner/node/Patterns.java | 4 ++
.../optimizations/LogicalOptimizeFactory.java | 2 +
.../optimizations/UnaliasSymbolReferences.java | 15 ++++++-
.../relational/analyzer/ExplainAnalyzeTest.java | 43 +++++++++++++++++++
.../plan/relational/planner/PlanTester.java | 8 ++--
.../planner/assertions/PlanMatchPattern.java | 13 ++++++
10 files changed, 165 insertions(+), 11 deletions(-)
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
index cfaff4fdc87..c49e3de9004 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
@@ -71,6 +71,7 @@ import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.AssignUnique
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.DeviceTableScanNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.EnforceSingleRowNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExchangeNode;
+import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExplainAnalyzeNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.GapFillNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.LinearFillNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.MarkDistinctNode;
@@ -821,6 +822,14 @@ public class PlanGraphPrinter extends
PlanVisitor<List<String>, PlanGraphPrinter
return render(node, boxValue, context);
}
+ @Override
+ public List<String> visitExplainAnalyze(ExplainAnalyzeNode node,
GraphContext context) {
+ List<String> boxValue = new ArrayList<>();
+ boxValue.add(String.format("ExplainAnalyze-%s",
node.getPlanNodeId().getId()));
+ boxValue.add(String.format("ChildPermittedOutputs: %s",
node.getChildPermittedOutputs()));
+ return render(node, boxValue, context);
+ }
+
@Override
public List<String> visitGapFill(GapFillNode node, GraphContext context) {
List<String> boxValue = new ArrayList<>();
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableLogicalPlanner.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableLogicalPlanner.java
index c9bfb879181..6f92192c092 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableLogicalPlanner.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableLogicalPlanner.java
@@ -480,6 +480,16 @@ public class TableLogicalPlanner {
createRelationPlan(analysis, (Query) (statement.getStatement()));
Symbol symbol =
symbolAllocator.newSymbol(ColumnHeaderConstant.EXPLAIN_ANALYZE,
StringType.getInstance());
+
+ // recording permittedOutputs of ExplainAnalyzeNode's child
+ RelationType outputDescriptor =
analysis.getOutputDescriptor(statement.getStatement());
+ ImmutableList.Builder<Symbol> childPermittedOutputs =
ImmutableList.builder();
+ for (Field field : outputDescriptor.getVisibleFields()) {
+ int fieldIndex = outputDescriptor.indexOf(field);
+ Symbol columnSymbol = originalQueryPlan.getSymbol(fieldIndex);
+ childPermittedOutputs.add(columnSymbol);
+ }
+
PlanNode newRoot =
new ExplainAnalyzeNode(
queryContext.getQueryId().genPlanNodeId(),
@@ -487,7 +497,8 @@ public class TableLogicalPlanner {
statement.isVerbose(),
queryContext.getLocalQueryId(),
queryContext.getTimeOut(),
- symbol);
+ symbol,
+ childPermittedOutputs.build());
return new RelationPlan(
newRoot,
originalQueryPlan.getScope(),
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneExplainAnalyzeColumns.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneExplainAnalyzeColumns.java
new file mode 100644
index 00000000000..697c1a55a8d
--- /dev/null
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneExplainAnalyzeColumns.java
@@ -0,0 +1,49 @@
+/*
+ * 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.iotdb.db.queryengine.plan.relational.planner.iterative.rule;
+
+import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.Rule;
+import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExplainAnalyzeNode;
+import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Captures;
+import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Pattern;
+
+import com.google.common.collect.ImmutableSet;
+
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.Util.restrictChildOutputs;
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.node.Patterns.explainAnalyze;
+
+public class PruneExplainAnalyzeColumns implements Rule<ExplainAnalyzeNode> {
+ private static final Pattern<ExplainAnalyzeNode> PATTERN = explainAnalyze();
+
+ @Override
+ public Pattern<ExplainAnalyzeNode> getPattern() {
+ return PATTERN;
+ }
+
+ @Override
+ public Result apply(ExplainAnalyzeNode analyzeNode, Captures captures,
Context context) {
+ return restrictChildOutputs(
+ context.getIdAllocator(),
+ analyzeNode,
+ ImmutableSet.copyOf(analyzeNode.getChildPermittedOutputs()))
+ .map(Result::ofPlanNode)
+ .orElse(Result.empty());
+ }
+}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ExplainAnalyzeNode.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ExplainAnalyzeNode.java
index 7332743050c..23aa8baad2d 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ExplainAnalyzeNode.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ExplainAnalyzeNode.java
@@ -37,6 +37,7 @@ public class ExplainAnalyzeNode extends
SingleChildProcessNode {
private final long queryId;
private final long timeout;
private final Symbol outputSymbol;
+ private final List<Symbol> childPermittedOutputs;
public ExplainAnalyzeNode(
PlanNodeId id,
@@ -44,17 +45,20 @@ public class ExplainAnalyzeNode extends
SingleChildProcessNode {
boolean verbose,
long queryId,
long timeout,
- Symbol outputSymbol) {
+ Symbol outputSymbol,
+ List<Symbol> childPermittedOutputs) {
super(id, child);
this.verbose = verbose;
this.timeout = timeout;
this.queryId = queryId;
this.outputSymbol = outputSymbol;
+ this.childPermittedOutputs = childPermittedOutputs;
}
@Override
public PlanNode clone() {
- return new ExplainAnalyzeNode(getPlanNodeId(), child, verbose, queryId,
timeout, outputSymbol);
+ return new ExplainAnalyzeNode(
+ getPlanNodeId(), child, verbose, queryId, timeout, outputSymbol,
childPermittedOutputs);
}
@Override
@@ -72,10 +76,20 @@ public class ExplainAnalyzeNode extends
SingleChildProcessNode {
return Collections.singletonList(outputSymbol);
}
+ public List<Symbol> getChildPermittedOutputs() {
+ return childPermittedOutputs;
+ }
+
@Override
public PlanNode replaceChildren(List<PlanNode> newChildren) {
return new
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExplainAnalyzeNode(
- getPlanNodeId(), newChildren.get(0), verbose, queryId, timeout,
outputSymbol);
+ getPlanNodeId(),
+ newChildren.get(0),
+ verbose,
+ queryId,
+ timeout,
+ outputSymbol,
+ childPermittedOutputs);
}
// ExplainAnalyze should be at the same region as Coordinator all the time.
Therefore, there will
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/Patterns.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/Patterns.java
index 83391f24d3f..1ebc30a72ed 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/Patterns.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/Patterns.java
@@ -133,6 +133,10 @@ public final class Patterns {
return typeOf(OutputNode.class);
}
+ public static Pattern<ExplainAnalyzeNode> explainAnalyze() {
+ return typeOf(ExplainAnalyzeNode.class);
+ }
+
public static Pattern<ProjectNode> project() {
return typeOf(ProjectNode.class);
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/LogicalOptimizeFactory.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/LogicalOptimizeFactory.java
index 36f0213da1c..aded13969d4 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/LogicalOptimizeFactory.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/LogicalOptimizeFactory.java
@@ -43,6 +43,7 @@ import
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.Pr
import
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneCorrelatedJoinCorrelation;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneDistinctAggregation;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneEnforceSingleRowColumns;
+import
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneExplainAnalyzeColumns;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneFillColumns;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneFilterColumns;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneGapFillColumns;
@@ -115,6 +116,7 @@ public class LogicalOptimizeFactory {
new PruneMarkDistinctColumns(),
new PruneOffsetColumns(),
new PruneOutputSourceColumns(),
+ new PruneExplainAnalyzeColumns(),
new PruneProjectColumns(),
new PruneSortColumns(),
new PruneTableFunctionProcessorSourceColumns(),
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/UnaliasSymbolReferences.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/UnaliasSymbolReferences.java
index 124bddf1e5c..abda59b797a 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/UnaliasSymbolReferences.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/UnaliasSymbolReferences.java
@@ -351,10 +351,21 @@ public class UnaliasSymbolReferences implements
PlanOptimizer {
@Override
public PlanAndMappings visitExplainAnalyze(ExplainAnalyzeNode node,
UnaliasContext context) {
PlanAndMappings rewrittenSource = node.getChild().accept(this, context);
+ Map<Symbol, Symbol> mapping = new
HashMap<>(rewrittenSource.getMappings());
+ SymbolMapper mapper = symbolMapper(mapping);
+
+ List<Symbol> newChildPermittedOutputs =
mapper.map(node.getChildPermittedOutputs());
return new PlanAndMappings(
- node.replaceChildren(ImmutableList.of(rewrittenSource.getRoot())),
- rewrittenSource.getMappings());
+ new ExplainAnalyzeNode(
+ node.getPlanNodeId(),
+ rewrittenSource.getRoot(),
+ node.isVerbose(),
+ node.getQueryId(),
+ node.getTimeout(),
+ node.getOutputSymbols().get(0),
+ newChildPermittedOutputs),
+ mapping);
}
@Override
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/ExplainAnalyzeTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/ExplainAnalyzeTest.java
new file mode 100644
index 00000000000..f20ebab3e98
--- /dev/null
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/ExplainAnalyzeTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.iotdb.db.queryengine.plan.relational.analyzer;
+
+import org.apache.iotdb.db.queryengine.plan.planner.plan.LogicalQueryPlan;
+import org.apache.iotdb.db.queryengine.plan.relational.planner.PlanTester;
+
+import org.junit.Test;
+
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanAssert.assertPlan;
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.aggregation;
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.aggregationTableScan;
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.explainAnalyze;
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.output;
+import static
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.project;
+
+public class ExplainAnalyzeTest {
+ private final PlanTester planTester = new PlanTester();
+
+ @Test
+ public void testColumnPrune() {
+ LogicalQueryPlan logicalQueryPlan =
+ planTester.createPlan("explain analyze select count(s1) from table1
group by tag1");
+ assertPlan(
+ logicalQueryPlan,
output(explainAnalyze(project(aggregation(aggregationTableScan())))));
+ }
+}
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
index 9a98ab96c7b..8eb019db607 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
@@ -115,7 +115,7 @@ public class PlanTester {
distributedQueryPlan = null;
MPPQueryContext context = new MPPQueryContext(sql, queryId, sessionInfo,
null, null);
- Analysis analysis = analyze(sql, metadata);
+ Analysis analysis = analyze(sql, metadata, context);
this.analysis = analysis;
this.symbolAllocator = new SymbolAllocator();
@@ -137,7 +137,7 @@ public class PlanTester {
distributedQueryPlan = null;
MPPQueryContext context = new MPPQueryContext(sql, queryId, sessionInfo,
null, null);
- Analysis analysis = analyze(sql, metadata);
+ Analysis analysis = analyze(sql, metadata, context);
TableLogicalPlanner logicalPlanner =
new TableLogicalPlanner(
@@ -146,7 +146,7 @@ public class PlanTester {
return logicalPlanner.plan(analysis);
}
- public static Analysis analyze(String sql, Metadata metadata) {
+ public static Analysis analyze(String sql, Metadata metadata,
MPPQueryContext context) {
SqlParser sqlParser = new SqlParser();
String databaseName;
if (metadata instanceof TSBSMetadata) {
@@ -160,8 +160,6 @@ public class PlanTester {
SessionInfo session =
new SessionInfo(
0, "test", ZoneId.systemDefault(), databaseName,
IClientSession.SqlDialect.TABLE);
- final MPPQueryContext context =
- new MPPQueryContext(sql, new QueryId("test_query"), session, null,
null);
return analyzeStatement(
statement, metadata, context, sqlParser, session, new
AllowAllAccessControl());
}
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
index aae5c1191f6..7206b1792ec 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
@@ -34,6 +34,7 @@ import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.CollectNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.DeviceTableScanNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.EnforceSingleRowNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExchangeNode;
+import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExplainAnalyzeNode;
import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
import
org.apache.iotdb.db.queryengine.plan.relational.planner.node.InformationSchemaTableScanNode;
import org.apache.iotdb.db.queryengine.plan.relational.planner.node.JoinNode;
@@ -250,6 +251,10 @@ public final class PlanMatchPattern {
return this;
}
+ public static PlanMatchPattern aggregation(PlanMatchPattern source) {
+ return node(AggregationNode.class, source);
+ }
+
public static PlanMatchPattern aggregation(
Map<String, ExpectedValueProvider<AggregationFunction>> aggregations,
PlanMatchPattern source) {
@@ -415,6 +420,10 @@ public final class PlanMatchPattern {
return result;
}
+ public static PlanMatchPattern aggregationTableScan() {
+ return node(AggregationTableScanNode.class);
+ }
+
public static PlanMatchPattern markDistinct(
String markerSymbol, List<String> distinctSymbols, PlanMatchPattern
source) {
return node(MarkDistinctNode.class, source)
@@ -566,6 +575,10 @@ public final class PlanMatchPattern {
return output(outputs, source).withExactOutputs(outputs);
}
+ public static PlanMatchPattern explainAnalyze(PlanMatchPattern source) {
+ return node(ExplainAnalyzeNode.class, source);
+ }
+
public static PlanMatchPattern project(PlanMatchPattern source) {
return node(ProjectNode.class, source);
}