[Improvement](expr) fold child when const expr not folded (#38493) (#38961)

cherry-pick from master 38493

1. fold child when const expr not folded
2. do not fold function `sleep`
3. move all exceptional expression into shouldSkipFold

before

mysql [test]>explain select sleep(sign(1)*100);
+-----------------------------------------------+
| Explain String(Nereids Planner)               |
+-----------------------------------------------+
| PLAN FRAGMENT 0                               |
|   OUTPUT EXPRS:                               |
|     sleep(cast((sign(1.0) * 100) as INT))[#0] |
|   PARTITION: UNPARTITIONED                    |
|                                               |
|   HAS_COLO_PLAN_NODE: false                   |
|                                               |
|   VRESULT SINK                                |
|      MYSQL_PROTOCAL                           |
|                                               |
|   0:VUNION(32)                                |
|      constant exprs:                          |
|          sleep(CAST((sign(1) * 100) AS int))  |
+-----------------------------------------------+
13 rows in set (15.02 sec)

mysql [test]>select sleep(sign(1)*100);
+-----------------------------------------------------+
| sleep(cast((sign(cast(1 as DOUBLE)) * 100) as INT)) |
+-----------------------------------------------------+
|                                                   1 |
+-----------------------------------------------------+
1 row in set (1 min 55.34 sec)


after

mysql [test]>explain select sleep(sign(1)*100);
+---------------------------------+
| Explain String(Nereids Planner) |
+---------------------------------+
| PLAN FRAGMENT 0                 |
|   OUTPUT EXPRS:                 |
|     sleep(100)[#0]              |
|   PARTITION: UNPARTITIONED      |
|                                 |
|   HAS_COLO_PLAN_NODE: false     |
|                                 |
|   VRESULT SINK                  |
|      MYSQL_PROTOCAL             |
|                                 |
|   0:VUNION(32)                  |
|      constant exprs:            |
|          sleep(100)             |
+---------------------------------+
13 rows in set (0.23 sec)

mysql [test]> select sleep(sign(1)*100);
+-----------------------------------------------------+
| sleep(cast((sign(cast(1 as DOUBLE)) * 100) as INT)) |
+-----------------------------------------------------+
|                                                   1 |
+-----------------------------------------------------+
1 row in set (1 min 40.37 sec)


Co-authored-by: Pxl <pxl290@qq.com>
This commit is contained in:
LiBinfeng
2024-08-12 15:13:48 +08:00
committed by GitHub
parent 635ea39aaf
commit 0c39b88804
4 changed files with 90 additions and 46 deletions

View File

@ -37,7 +37,10 @@ import org.apache.doris.nereids.trees.expressions.ArrayItemReference;
import org.apache.doris.nereids.trees.expressions.Cast;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Match;
import org.apache.doris.nereids.trees.expressions.functions.BoundFunction;
import org.apache.doris.nereids.trees.expressions.functions.generator.TableGeneratingFunction;
import org.apache.doris.nereids.trees.expressions.functions.scalar.NonNullable;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Nullable;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Sleep;
import org.apache.doris.nereids.trees.expressions.literal.ArrayLiteral;
import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
@ -55,7 +58,6 @@ import org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.literal.MapLiteral;
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
import org.apache.doris.nereids.trees.expressions.literal.NumericLiteral;
import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral;
import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
import org.apache.doris.nereids.trees.expressions.literal.StructLiteral;
@ -157,7 +159,11 @@ public class FoldConstantRuleOnBE implements ExpressionPatternRuleFactory {
Expression root, Map<String, Expression> constMap, Map<String, Expression> resultMap) {
for (Entry<String, Expression> entry : constMap.entrySet()) {
if (entry.getValue().equals(root)) {
return resultMap.get(entry.getKey());
if (resultMap.containsKey(entry.getKey())) {
return resultMap.get(entry.getKey());
} else {
return root;
}
}
}
List<Expression> newChildren = new ArrayList<>();
@ -174,38 +180,7 @@ public class FoldConstantRuleOnBE implements ExpressionPatternRuleFactory {
private static void collectConst(Expression expr, Map<String, Expression> constMap,
Map<String, TExpr> tExprMap, IdGenerator<ExprId> idGenerator) {
if (expr.isConstant()) {
// Do not constant fold cast(null as dataType) because we cannot preserve the
// cast-to-types and that can lead to query failures, e.g., CTAS
if (expr instanceof Cast) {
if (((Cast) expr).child().isNullLiteral()) {
return;
}
if (skipSleepFunction(((Cast) expr).child())) {
return;
}
}
// skip literal expr
if (expr.isLiteral()) {
return;
}
// eg: avg_state(1) return is agg function serialize data
// and some type can't find a literal to represent.
// time type: need add a time literal in nereids
// IPv6 type: need get a library to output the compressed address format
if (expr.getDataType().isAggStateType() || expr.getDataType().isObjectType()
|| expr.getDataType().isVariantType() || expr.getDataType().isTimeLikeType()
|| expr.getDataType().isIPv6Type()) {
return;
}
// first need pass PlanTranslatorContext value,
// and ArrayItemReference translate, can't findColumnRef
// Match need give more info rather then as left child a NULL, in
// match_phrase_prefix/MATCH_PHRASE/MATCH_PHRASE/MATCH_ANY
if (skipSleepFunction(expr) || (expr instanceof TableGeneratingFunction)
|| (expr instanceof ArrayItemReference) || (expr instanceof Match)) {
return;
}
if (expr.isConstant() && !shouldSkipFold(expr)) {
String id = idGenerator.getNextId().toString();
constMap.put(id, expr);
Expr staleExpr;
@ -229,17 +204,58 @@ public class FoldConstantRuleOnBE implements ExpressionPatternRuleFactory {
}
}
// if sleep(5) will cause rpc timeout
private static boolean skipSleepFunction(Expression expr) {
if (expr instanceof Sleep) {
Expression param = expr.child(0);
if (param instanceof Cast) {
param = param.child(0);
}
if (param instanceof NumericLiteral) {
return ((NumericLiteral) param).getDouble() >= 5.0;
}
// Some expressions should not do constant folding
private static boolean shouldSkipFold(Expression expr) {
// Skip literal expr
if (expr.isLiteral()) {
return true;
}
// Frontend can not represent those types
if (expr.getDataType().isAggStateType() || expr.getDataType().isObjectType()
|| expr.getDataType().isVariantType() || expr.getDataType().isTimeLikeType()
|| expr.getDataType().isIPv6Type()) {
return true;
}
// Frontend can not represent geo types
if (expr instanceof BoundFunction && ((BoundFunction) expr).getName().toLowerCase().startsWith("st_")) {
return true;
}
// TableGeneratingFunction need pass PlanTranslatorContext value
if (expr instanceof TableGeneratingFunction) {
return true;
}
// ArrayItemReference translate can't findColumnRef
if (expr instanceof ArrayItemReference) {
return true;
}
// Match need give more info rather then as left child a NULL, in
// match_phrase_prefix/MATCH_PHRASE/MATCH_PHRASE/MATCH_ANY
if (expr instanceof Match) {
return true;
}
// sleep will cause rpc timeout
if (expr instanceof Sleep) {
return true;
}
// Do not constant fold cast(null as dataType) because we cannot preserve the
// cast-to-types and that can lead to query failures, e.g., CTAS
if (expr instanceof Cast && ((Cast) expr).child().isNullLiteral()) {
return true;
}
// This kind of function is often used to change the attributes of columns.
// Folding will make it impossible to construct columns such as nullable(1).
if (expr instanceof Nullable || expr instanceof NonNullable) {
return true;
}
return false;
}