diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/Metadata.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/Metadata.java index cfabb03c6aa..22e8acec47b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/Metadata.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/Metadata.java @@ -185,7 +185,8 @@ public interface Metadata { final String database, final List sgNameToQueryParamsMap); /** + * @param withTime some function with time can also use Statistics, like first_by, last_by * @return if the Aggregation can use statistics to optimize */ - boolean canUseStatistics(final String name); + boolean canUseStatistics(final String name, boolean withTime); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableBuiltinAggregationFunction.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableBuiltinAggregationFunction.java index 09da97cdfe9..e14df7ee408 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableBuiltinAggregationFunction.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableBuiltinAggregationFunction.java @@ -76,7 +76,7 @@ public enum TableBuiltinAggregationFunction { /** * @return if the Aggregation can use statistics to optimize */ - public static boolean canUseStatistics(String name) { + public static boolean canUseStatistics(String name, boolean withTime) { final String functionName = name.toLowerCase(); switch (functionName) { case "sum": @@ -90,6 +90,7 @@ public enum TableBuiltinAggregationFunction { return true; case "first_by": case "last_by": + return withTime; case "mode": case "max_by": case "min_by": diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java index 084d098d747..43040121845 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/metadata/TableMetadataImpl.java @@ -705,8 +705,8 @@ public class TableMetadataImpl implements Metadata { } @Override - public boolean canUseStatistics(String functionName) { - return TableBuiltinAggregationFunction.canUseStatistics(functionName); + public boolean canUseStatistics(String functionName, boolean withTime) { + return TableBuiltinAggregationFunction.canUseStatistics(functionName, withTime); } public static boolean isTwoNumericType(List argumentTypes) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushAggregationIntoTableScan.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushAggregationIntoTableScan.java index 5b383d50ffc..771135627c9 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushAggregationIntoTableScan.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushAggregationIntoTableScan.java @@ -139,7 +139,13 @@ public class PushAggregationIntoTableScan implements PlanOptimizer { for (AggregationNode.Aggregation aggregation : values) { // if the function cannot make use of Statistics, we don't push down if (!metadata.canUseStatistics( - aggregation.getResolvedFunction().getSignature().getName())) { + aggregation.getResolvedFunction().getSignature().getName(), + aggregation.getArguments().stream() + .anyMatch( + v -> + ((SymbolReference) v) + .getName() + .equalsIgnoreCase(TimestampOperand.TIMESTAMP_EXPRESSION_STRING)))) { return PushDownLevel.NOOP; } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AggregationTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AggregationTest.java index 8ea55c73134..2aa5158060f 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AggregationTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AggregationTest.java @@ -657,4 +657,29 @@ public class AggregationTest { ImmutableList.of("time", "s1", "s2"), ImmutableSet.of("s1", "s2", "time")))))); } + + @Test + public void withTimePushDownLevelTest() { + PlanTester planTester = new PlanTester(); + + // first, last, first_by with time, last_by with time should be push-down + LogicalQueryPlan logicalQueryPlan = + planTester.createPlan( + "SELECT first(s1), last(s1), first_by(time,s1), last_by(time,s1) FROM table1 group by tag1, tag2, tag3"); + + // Output - Project - AggregationTableScan + assertPlan( + logicalQueryPlan, + output( + project( + aggregationTableScan( + singleGroupingSet("tag1", "tag2", "tag3"), + ImmutableList.of("tag1", "tag2", "tag3"), // Streamable + Optional.empty(), + SINGLE, + "testdb.table1", + ImmutableList.of( + "tag1", "tag2", "tag3", "first", "last", "first_by", "last_by"), + ImmutableSet.of("tag1", "tag2", "tag3", "s1", "time"))))); + } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TSBSMetadata.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TSBSMetadata.java index f01b4400cb3..244a1a8f496 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TSBSMetadata.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TSBSMetadata.java @@ -365,8 +365,8 @@ public class TSBSMetadata implements Metadata { } @Override - public boolean canUseStatistics(String name) { - return TableBuiltinAggregationFunction.canUseStatistics(name); + public boolean canUseStatistics(String name, boolean withTime) { + return TableBuiltinAggregationFunction.canUseStatistics(name, withTime); } private static final DataPartition DATA_PARTITION = diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java index f6d2678a812..d6c7d1b15ba 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java @@ -312,8 +312,8 @@ public class TestMatadata implements Metadata { } @Override - public boolean canUseStatistics(String name) { - return TableBuiltinAggregationFunction.canUseStatistics(name); + public boolean canUseStatistics(String name, boolean withTime) { + return TableBuiltinAggregationFunction.canUseStatistics(name, withTime); } private static final DataPartition DATA_PARTITION =