This is an automated email from the ASF dual-hosted git repository.
englefly pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 423002b20a [fix](nereids) partitionTopN & Window estimation (#22953)
423002b20a is described below
commit 423002b20a3ae9da74898051835b3514a7f87db2
Author: minghong <[email protected]>
AuthorDate: Tue Aug 15 20:19:03 2023 +0800
[fix](nereids) partitionTopN & Window estimation (#22953)
* partitionTopN & winExpr estimation
* tpcds 44/47/57
---
.../doris/nereids/stats/ExpressionEstimation.java | 18 ++--
.../doris/nereids/stats/StatsCalculator.java | 109 ++++++++++++++-------
.../plans/physical/PhysicalPartitionTopN.java | 3 +-
.../trees/plans/physical/PhysicalQuickSort.java | 2 +-
.../trees/plans/physical/PhysicalWindow.java | 2 +-
.../nereids_tpcds_shape_sf100_p0/shape/query44.out | 62 ++++++------
.../nereids_tpcds_shape_sf100_p0/shape/query47.out | 19 ++--
.../nereids_tpcds_shape_sf100_p0/shape/query57.out | 20 ++--
8 files changed, 135 insertions(+), 100 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
index 03e4be4d63..5324fce9e6 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java
@@ -290,13 +290,12 @@ public class ExpressionEstimation extends
ExpressionVisitor<ColumnStatistic, Sta
}
/*
we keep columnStat.min and columnStat.max, but set ndv=1.
- if there is group-by keys, we will update ndv when visiting group
clause
+ if there is group-by keys, we will update count when visiting group
clause
*/
double width = min.child().getDataType().width();
- return new
ColumnStatisticBuilder().setCount(1).setNdv(1).setAvgSizeByte(width).setNumNulls(width)
-
.setDataSize(child.getDataType().width()).setMinValue(columnStat.minValue)
- .setMaxValue(columnStat.maxValue).setSelectivity(1.0)
- .setMinExpr(null).build();
+ return new
ColumnStatisticBuilder().setCount(1).setNdv(1).setAvgSizeByte(width)
+
.setMinValue(columnStat.minValue).setMinExpr(columnStat.minExpr)
+
.setMaxValue(columnStat.maxValue).setMaxExpr(columnStat.maxExpr).build();
}
@Override
@@ -308,12 +307,13 @@ public class ExpressionEstimation extends
ExpressionVisitor<ColumnStatistic, Sta
}
/*
we keep columnStat.min and columnStat.max, but set ndv=1.
- if there is group-by keys, we will update ndv when visiting group
clause
+ if there is group-by keys, we will update count when visiting group
clause
*/
int width = max.child().getDataType().width();
- return new
ColumnStatisticBuilder().setCount(1D).setNdv(1D).setAvgSizeByte(width).setNumNulls(0)
-
.setDataSize(width).setMinValue(columnStat.minValue).setMaxValue(columnStat.maxValue)
- .setSelectivity(1.0).setMaxExpr(null).setMinExpr(null).build();
+ return new
ColumnStatisticBuilder().setCount(1D).setNdv(1D).setAvgSizeByte(width)
+
.setMinValue(columnStat.minValue).setMinExpr(columnStat.minExpr)
+
.setMaxValue(columnStat.maxValue).setMaxExpr(columnStat.maxExpr)
+ .build();
}
@Override
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java
index 5f7b4cc3de..380d34dd1d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java
@@ -17,6 +17,7 @@
package org.apache.doris.nereids.stats;
+import org.apache.doris.analysis.IntLiteral;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.OlapTable;
@@ -38,7 +39,9 @@ import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.expressions.WindowExpression;
import
org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction;
-import org.apache.doris.nereids.trees.expressions.functions.window.Rank;
+import org.apache.doris.nereids.trees.expressions.functions.agg.Count;
+import org.apache.doris.nereids.trees.expressions.functions.agg.Max;
+import org.apache.doris.nereids.trees.expressions.functions.agg.Min;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation;
@@ -681,16 +684,20 @@ public class StatsCalculator extends
DefaultPlanVisitor<Statistics, Void> {
}
private Statistics computePartitionTopN(PartitionTopN partitionTopN) {
- Statistics stats = groupExpression.childStatistics(0);
- double rowCount = stats.getRowCount();
+ Statistics childStats = groupExpression.childStatistics(0);
+ double rowCount = childStats.getRowCount();
List<Expression> partitionKeys = partitionTopN.getPartitionKeys();
if (!partitionTopN.hasGlobalLimit() && !partitionKeys.isEmpty()) {
// If there is no global limit. So result for the cardinality
estimation is:
// NDV(partition key) * partitionLimit
- Map<Expression, ColumnStatistic> childSlotToColumnStats =
stats.columnStatistics();
List<ColumnStatistic> partitionByKeyStats = partitionKeys.stream()
- .filter(childSlotToColumnStats::containsKey)
- .map(childSlotToColumnStats::get)
+ .map(partitionKey -> {
+ ColumnStatistic partitionKeyStats =
childStats.findColumnStatistics(partitionKey);
+ if (partitionKeyStats == null) {
+ partitionKeyStats = new
ExpressionEstimation().visit(partitionKey, childStats);
+ }
+ return partitionKeyStats;
+ })
.filter(s -> !s.isUnKnown)
.collect(Collectors.toList());
if (partitionByKeyStats.isEmpty()) {
@@ -698,7 +705,7 @@ public class StatsCalculator extends
DefaultPlanVisitor<Statistics, Void> {
rowCount = rowCount * DEFAULT_COLUMN_NDV_RATIO;
} else {
rowCount = Math.min(rowCount,
partitionByKeyStats.stream().map(s -> s.ndv)
- .max(Double::compare).get());
+ .max(Double::compare).get() *
partitionTopN.getPartitionLimit());
}
} else {
rowCount = Math.min(rowCount, partitionTopN.getPartitionLimit());
@@ -706,7 +713,7 @@ public class StatsCalculator extends
DefaultPlanVisitor<Statistics, Void> {
// TODO: for the filter push down window situation, we will prune the
row count twice
// because we keep the pushed down filter. And it will be calculated
twice, one of them in 'PartitionTopN'
// and the other is in 'Filter'. It's hard to dismiss.
- return stats.updateRowCountOnly(rowCount);
+ return childStats.updateRowCountOnly(rowCount);
}
private Statistics computeLimit(Limit limit) {
@@ -961,42 +968,72 @@ public class StatsCalculator extends
DefaultPlanVisitor<Statistics, Void> {
}
private Statistics computeWindow(Window windowOperator) {
- Statistics stats = groupExpression.childStatistics(0);
- Map<Expression, ColumnStatistic> childColumnStats =
stats.columnStatistics();
+ Statistics childStats = groupExpression.childStatistics(0);
+ Map<Expression, ColumnStatistic> childColumnStats =
childStats.columnStatistics();
Map<Expression, ColumnStatistic> columnStatisticMap =
windowOperator.getWindowExpressions().stream()
.map(expr -> {
- //estimate rank()
- if (expr instanceof Alias && expr.child(0) instanceof
WindowExpression
- && ((WindowExpression)
expr.child(0)).getFunction() instanceof Rank) {
- ColumnStatisticBuilder colBuilder = new
ColumnStatisticBuilder();
- colBuilder.setNdv(stats.getRowCount())
- .setOriginal(null)
- .setCount(stats.getRowCount())
- .setMinValue(0)
- .setMaxValue(stats.getRowCount());
- return Pair.of(expr.toSlot(), colBuilder.build());
- }
- //estimate other expressions
- ColumnStatistic value = null;
- Set<Slot> slots = expr.getInputSlots();
- if (slots.isEmpty()) {
- value = ColumnStatistic.UNKNOWN;
+ Preconditions.checkArgument(expr instanceof Alias
+ && expr.child(0) instanceof WindowExpression,
+ "need WindowExpression, but we meet " + expr);
+ WindowExpression windExpr = (WindowExpression)
expr.child(0);
+ ColumnStatisticBuilder colStatsBuilder = new
ColumnStatisticBuilder();
+ colStatsBuilder.setCount(childStats.getRowCount())
+ .setOriginal(null);
+
+ Double partitionCount =
windExpr.getPartitionKeys().stream().map(key -> {
+ ColumnStatistic keyStats =
childStats.findColumnStatistics(key);
+ if (keyStats == null) {
+ keyStats = new ExpressionEstimation().visit(key,
childStats);
+ }
+ return keyStats;
+ })
+ .filter(columnStatistic ->
!columnStatistic.isUnKnown)
+ .map(colStats -> colStats.ndv).max(Double::compare)
+ .orElseGet(() -> -1.0);
+
+ if (partitionCount == -1.0) {
+ // partition key stats are all unknown
+ colStatsBuilder.setCount(childStats.getRowCount())
+ .setNdv(1)
+ .setMinValue(Double.NEGATIVE_INFINITY)
+ .setMaxValue(Double.POSITIVE_INFINITY);
} else {
- for (Slot slot : slots) {
- if (childColumnStats.containsKey(slot)) {
- value = childColumnStats.get(slot);
- break;
+ partitionCount = Math.max(1, partitionCount);
+ if (windExpr.getFunction() instanceof
AggregateFunction) {
+ if (windExpr.getFunction() instanceof Count) {
+ colStatsBuilder.setNdv(1)
+ .setMinValue(0)
+ .setMinExpr(new IntLiteral(0))
+ .setMaxValue(childStats.getRowCount())
+ .setMaxExpr(new IntLiteral((long)
childStats.getRowCount()));
+ } else if (windExpr.getFunction() instanceof Min
+ || windExpr.getFunction() instanceof Max) {
+ Expression minmaxChild =
windExpr.getFunction().child(0);
+ ColumnStatistic minChildStats = new
ExpressionEstimation()
+ .visit(minmaxChild, childStats);
+ colStatsBuilder.setNdv(1)
+ .setMinValue(minChildStats.minValue)
+ .setMinExpr(minChildStats.minExpr)
+ .setMaxValue(minChildStats.maxValue)
+ .setMaxExpr(minChildStats.maxExpr);
+ } else {
+ // sum/avg
+
colStatsBuilder.setNdv(1).setMinValue(Double.NEGATIVE_INFINITY)
+ .setMaxValue(Double.POSITIVE_INFINITY);
}
- }
- if (value == null) {
- // todo: how to set stats?
- value = ColumnStatistic.UNKNOWN;
+ } else {
+ // rank/dense_rank/row_num ...
+ colStatsBuilder.setNdv(childStats.getRowCount() /
partitionCount)
+ .setMinValue(0)
+ .setMinExpr(new IntLiteral(0))
+ .setMaxValue(childStats.getRowCount())
+ .setMaxExpr(new IntLiteral((long)
childStats.getRowCount()));
}
}
- return Pair.of(expr.toSlot(), value);
+ return Pair.of(expr.toSlot(), colStatsBuilder.build());
}).collect(Collectors.toMap(Pair::key, Pair::value));
columnStatisticMap.putAll(childColumnStats);
- return new Statistics(stats.getRowCount(), columnStatisticMap);
+ return new Statistics(childStats.getRowCount(), columnStatisticMap);
}
private ColumnStatistic unionColumn(ColumnStatistic leftStats, double
leftRowCount, ColumnStatistic rightStats,
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPartitionTopN.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPartitionTopN.java
index ce57ad0782..4166e7d903 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPartitionTopN.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPartitionTopN.java
@@ -183,7 +183,8 @@ public class PhysicalPartitionTopN<CHILD_TYPE extends Plan>
extends PhysicalUnar
"partitionKeys", partitionKeys,
"orderKeys", orderKeys,
"hasGlobalLimit", hasGlobalLimit,
- "partitionLimit", partitionLimit
+ "partitionLimit", partitionLimit,
+ "stats", statistics
);
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalQuickSort.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalQuickSort.java
index 5981c8e538..57c77cc4fb 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalQuickSort.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalQuickSort.java
@@ -103,7 +103,7 @@ public class PhysicalQuickSort<CHILD_TYPE extends Plan>
extends AbstractPhysical
public String toString() {
return Utils.toSqlString("PhysicalQuickSort[" + id.asInt() + "]" +
getGroupIdWithPrefix(),
"orderKeys", orderKeys,
- "phase", phase.toString()
+ "phase", phase.toString(), "stats", statistics
);
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalWindow.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalWindow.java
index 5632e970a3..b1703f4749 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalWindow.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalWindow.java
@@ -106,7 +106,7 @@ public class PhysicalWindow<CHILD_TYPE extends Plan>
extends PhysicalUnary<CHILD
public String toString() {
return Utils.toSqlString("PhysicalWindow[" + id.asInt() + "]" +
getGroupIdWithPrefix(),
"windowFrameGroup", windowFrameGroup,
- "requiredProperties", requireProperties
+ "requiredProperties", requireProperties, "stats", statistics
);
}
diff --git
a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query44.out
b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query44.out
index ef988f8e86..8028e752fd 100644
--- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query44.out
+++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query44.out
@@ -5,11 +5,11 @@ PhysicalResultSink
----PhysicalDistribute
------PhysicalTopN
--------PhysicalProject
-----------hashJoin[INNER_JOIN](i1.i_item_sk = asceding.item_sk)
-------------PhysicalProject
---------------PhysicalOlapScan[item]
+----------hashJoin[INNER_JOIN](asceding.rnk = descending.rnk)
------------PhysicalDistribute
---------------hashJoin[INNER_JOIN](asceding.rnk = descending.rnk)
+--------------hashJoin[INNER_JOIN](i1.i_item_sk = asceding.item_sk)
+----------------PhysicalProject
+------------------PhysicalOlapScan[item]
----------------PhysicalDistribute
------------------PhysicalProject
--------------------filter((rnk < 11))
@@ -36,34 +36,34 @@ PhysicalResultSink
--------------------------------------------------PhysicalProject
----------------------------------------------------filter(ss_addr_sk IS
NULL(store_sales.ss_store_sk = 146))
------------------------------------------------------PhysicalOlapScan[store_sales]
+------------PhysicalDistribute
+--------------hashJoin[INNER_JOIN](i2.i_item_sk = descending.item_sk)
+----------------PhysicalProject
+------------------PhysicalOlapScan[item]
----------------PhysicalDistribute
-------------------hashJoin[INNER_JOIN](i2.i_item_sk = descending.item_sk)
---------------------PhysicalProject
-----------------------PhysicalOlapScan[item]
---------------------PhysicalDistribute
-----------------------PhysicalProject
-------------------------filter((rnk < 11))
---------------------------PhysicalWindow
+------------------PhysicalProject
+--------------------filter((rnk < 11))
+----------------------PhysicalWindow
+------------------------PhysicalQuickSort
+--------------------------PhysicalDistribute
----------------------------PhysicalQuickSort
-------------------------------PhysicalDistribute
---------------------------------PhysicalQuickSort
-----------------------------------PhysicalPartitionTopN
-------------------------------------PhysicalProject
---------------------------------------NestedLoopJoin[INNER_JOIN](cast(rank_col
as DOUBLE) > cast((0.9 * rank_col) as DOUBLE))
-----------------------------------------hashAgg[GLOBAL]
-------------------------------------------PhysicalDistribute
---------------------------------------------hashAgg[LOCAL]
-----------------------------------------------PhysicalProject
-------------------------------------------------filter((ss1.ss_store_sk = 146))
---------------------------------------------------PhysicalOlapScan[store_sales]
+------------------------------PhysicalPartitionTopN
+--------------------------------PhysicalProject
+----------------------------------NestedLoopJoin[INNER_JOIN](cast(rank_col as
DOUBLE) > cast((0.9 * rank_col) as DOUBLE))
+------------------------------------hashAgg[GLOBAL]
+--------------------------------------PhysicalDistribute
+----------------------------------------hashAgg[LOCAL]
+------------------------------------------PhysicalProject
+--------------------------------------------filter((ss1.ss_store_sk = 146))
+----------------------------------------------PhysicalOlapScan[store_sales]
+------------------------------------PhysicalDistribute
+--------------------------------------PhysicalAssertNumRows
----------------------------------------PhysicalDistribute
-------------------------------------------PhysicalAssertNumRows
---------------------------------------------PhysicalDistribute
-----------------------------------------------PhysicalProject
-------------------------------------------------hashAgg[GLOBAL]
---------------------------------------------------PhysicalDistribute
-----------------------------------------------------hashAgg[LOCAL]
-------------------------------------------------------PhysicalProject
---------------------------------------------------------filter(ss_addr_sk IS
NULL(store_sales.ss_store_sk = 146))
-----------------------------------------------------------PhysicalOlapScan[store_sales]
+------------------------------------------PhysicalProject
+--------------------------------------------hashAgg[GLOBAL]
+----------------------------------------------PhysicalDistribute
+------------------------------------------------hashAgg[LOCAL]
+--------------------------------------------------PhysicalProject
+----------------------------------------------------filter(ss_addr_sk IS
NULL(store_sales.ss_store_sk = 146))
+------------------------------------------------------PhysicalOlapScan[store_sales]
diff --git
a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query47.out
b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query47.out
index b705f7a2cb..3c6bf21b99 100644
--- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query47.out
+++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query47.out
@@ -36,17 +36,16 @@ PhysicalCteAnchor ( cteId=CTEId#0 )
----------PhysicalTopN
------------PhysicalProject
--------------hashJoin[INNER_JOIN](v1.i_category =
v1_lead.i_category)(v1.i_brand = v1_lead.i_brand)(v1.s_store_name =
v1_lead.s_store_name)(v1.s_company_name = v1_lead.s_company_name)(v1.rn =
expr_(rn - 1))
+----------------PhysicalProject
+------------------hashJoin[INNER_JOIN](v1.i_category =
v1_lag.i_category)(v1.i_brand = v1_lag.i_brand)(v1.s_store_name =
v1_lag.s_store_name)(v1.s_company_name = v1_lag.s_company_name)(v1.rn =
expr_(rn + 1))
+--------------------PhysicalDistribute
+----------------------PhysicalProject
+------------------------PhysicalCteConsumer ( cteId=CTEId#0 )
+--------------------PhysicalDistribute
+----------------------PhysicalProject
+------------------------filter((CASE WHEN (avg_monthly_sales > 0.0000) THEN
(abs((cast(sum_sales as DOUBLE) - cast(avg_monthly_sales as DOUBLE))) /
cast(avg_monthly_sales as DOUBLE)) ELSE NULL END > 0.1)(v2.d_year =
2001)(v2.avg_monthly_sales > 0.0000))
+--------------------------PhysicalCteConsumer ( cteId=CTEId#0 )
----------------PhysicalDistribute
------------------PhysicalProject
--------------------PhysicalCteConsumer ( cteId=CTEId#0 )
-----------------PhysicalDistribute
-------------------PhysicalProject
---------------------hashJoin[INNER_JOIN](v1.i_category =
v1_lag.i_category)(v1.i_brand = v1_lag.i_brand)(v1.s_store_name =
v1_lag.s_store_name)(v1.s_company_name = v1_lag.s_company_name)(v1.rn =
expr_(rn + 1))
-----------------------PhysicalDistribute
-------------------------PhysicalProject
---------------------------PhysicalCteConsumer ( cteId=CTEId#0 )
-----------------------PhysicalDistribute
-------------------------PhysicalProject
---------------------------filter((CASE WHEN (avg_monthly_sales > 0.0000) THEN
(abs((cast(sum_sales as DOUBLE) - cast(avg_monthly_sales as DOUBLE))) /
cast(avg_monthly_sales as DOUBLE)) ELSE NULL END > 0.1)(v2.d_year =
2001)(v2.avg_monthly_sales > 0.0000))
-----------------------------PhysicalCteConsumer ( cteId=CTEId#0 )
diff --git
a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query57.out
b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query57.out
index 2e7f06968a..71c2cdd060 100644
--- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query57.out
+++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query57.out
@@ -36,18 +36,16 @@ PhysicalCteAnchor ( cteId=CTEId#0 )
--------PhysicalDistribute
----------PhysicalTopN
------------PhysicalProject
---------------hashJoin[INNER_JOIN](v1.i_category =
v1_lead.i_category)(v1.i_brand = v1_lead.i_brand)(v1.cc_name =
v1_lead.cc_name)(v1.rn = expr_(rn - 1))
+--------------hashJoin[INNER_JOIN](v1.i_category =
v1_lag.i_category)(v1.i_brand = v1_lag.i_brand)(v1.cc_name =
v1_lag.cc_name)(v1.rn = expr_(rn + 1))
+----------------hashJoin[INNER_JOIN](v1.i_category =
v1_lead.i_category)(v1.i_brand = v1_lead.i_brand)(v1.cc_name =
v1_lead.cc_name)(v1.rn = expr_(rn - 1))
+------------------PhysicalDistribute
+--------------------PhysicalProject
+----------------------PhysicalCteConsumer ( cteId=CTEId#0 )
+------------------PhysicalDistribute
+--------------------PhysicalProject
+----------------------filter((CASE WHEN (avg_monthly_sales > 0.0000) THEN
(abs((cast(sum_sales as DOUBLE) - cast(avg_monthly_sales as DOUBLE))) /
cast(avg_monthly_sales as DOUBLE)) ELSE NULL END > 0.1)(v2.d_year =
1999)(v2.avg_monthly_sales > 0.0000))
+------------------------PhysicalCteConsumer ( cteId=CTEId#0 )
----------------PhysicalDistribute
------------------PhysicalProject
--------------------PhysicalCteConsumer ( cteId=CTEId#0 )
-----------------PhysicalDistribute
-------------------PhysicalProject
---------------------hashJoin[INNER_JOIN](v1.i_category =
v1_lag.i_category)(v1.i_brand = v1_lag.i_brand)(v1.cc_name =
v1_lag.cc_name)(v1.rn = expr_(rn + 1))
-----------------------PhysicalDistribute
-------------------------PhysicalProject
---------------------------PhysicalCteConsumer ( cteId=CTEId#0 )
-----------------------PhysicalDistribute
-------------------------PhysicalProject
---------------------------filter((CASE WHEN (avg_monthly_sales > 0.0000) THEN
(abs((cast(sum_sales as DOUBLE) - cast(avg_monthly_sales as DOUBLE))) /
cast(avg_monthly_sales as DOUBLE)) ELSE NULL END > 0.1)(v2.d_year =
1999)(v2.avg_monthly_sales > 0.0000))
-----------------------------PhysicalCteConsumer ( cteId=CTEId#0 )
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]