[Enhancement] support common expr reuse in complex case-when expr in scan predicates (#62779)
Signed-off-by: silverbullet233 <3675229+silverbullet233@users.noreply.github.com>
This commit is contained in:
parent
668fb46cad
commit
726fa67c3f
|
|
@ -18,11 +18,14 @@ import com.starrocks.catalog.Column;
|
|||
import com.starrocks.sql.optimizer.Utils;
|
||||
import com.starrocks.sql.optimizer.operator.OperatorType;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.BinaryPredicateOperator;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.CallOperator;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.CaseWhenOperator;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.ColumnRefOperator;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.CompoundPredicateOperator;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.ConstantOperator;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.LambdaFunctionOperator;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.ScalarOperator;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.ScalarOperatorUtil;
|
||||
import com.starrocks.sql.optimizer.operator.scalar.ScalarOperatorVisitor;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
|
@ -102,7 +105,7 @@ public class TableScanPredicateExtractor {
|
|||
}
|
||||
|
||||
// CanFullyPushDownVisitor is used to check whether a predicate can be pushed down into ScanNode.
|
||||
// currently, we only allow single-column predicates that not contain lambda expressions to be pushed down.
|
||||
// currently, we only allow single-column predicates that not contain lambda expressions and complex case-when to be pushed down.
|
||||
private class CanFullyPushDownVisitor extends ScalarOperatorVisitor<Boolean, CanFullyPushDownVisitorContext> {
|
||||
private final Map<ColumnRefOperator, Column> columnRefOperatorColumnMap;
|
||||
|
||||
|
|
@ -172,5 +175,17 @@ public class TableScanPredicateExtractor {
|
|||
public Boolean visitLambdaFunctionOperator(LambdaFunctionOperator op, CanFullyPushDownVisitorContext context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean visitCaseWhenOperator(CaseWhenOperator op, CanFullyPushDownVisitorContext context) {
|
||||
if (!visit(op, context)) {
|
||||
return false;
|
||||
}
|
||||
boolean containsCallOperator = op.getAllConditionClause().stream()
|
||||
.anyMatch(scalarOperator ->
|
||||
ScalarOperatorUtil.getStream(scalarOperator)
|
||||
.anyMatch(operator -> operator instanceof CallOperator));
|
||||
return !containsCallOperator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -315,6 +315,39 @@ public class ScanPredicateExprReuseTest extends PlanTestBase {
|
|||
" Pruned type: 7 <-> [MAP<INT,INT>]\n" +
|
||||
" ColumnAccessPath: [/v1/OFFSET, /v5/b/a/OFFSET, /v6/OFFSET]");
|
||||
}
|
||||
{
|
||||
String sql = "select * from tarray where " +
|
||||
"(case when array_length(v3) < 8 then 0 when array_length(v3) < 16 then 1 end) >= 1";
|
||||
String plan = getFragmentPlan(sql);
|
||||
assertContains(plan, " 2:SELECT\n" +
|
||||
" | predicates: CASE WHEN 4: array_length < 8 THEN 0 WHEN 4: array_length < 16 THEN 1 END >= 1\n" +
|
||||
" | \n" +
|
||||
" 1:Project\n" +
|
||||
" | <slot 1> : 1: v1\n" +
|
||||
" | <slot 2> : 2: v2\n" +
|
||||
" | <slot 3> : 3: v3\n" +
|
||||
" | <slot 4> : array_length(3: v3)");
|
||||
}
|
||||
{
|
||||
String sql = "select * from tarray where (case array_length(v3) when 1 then v1 when 2 then v2 end) >= 10";
|
||||
String plan = getFragmentPlan(sql);
|
||||
assertContains(plan, " 2:SELECT\n" +
|
||||
" | predicates: CASE 4: array_length WHEN 1 THEN 1: v1 WHEN 2 THEN 2: v2 END >= 10\n" +
|
||||
" | \n" +
|
||||
" 1:Project\n" +
|
||||
" | <slot 1> : 1: v1\n" +
|
||||
" | <slot 2> : 2: v2\n" +
|
||||
" | <slot 3> : 3: v3\n" +
|
||||
" | <slot 4> : array_length(3: v3)");
|
||||
}
|
||||
{
|
||||
String sql = "select * from t0 where (case when v1 > 1 then v1 + 10 when v1 > 2 then v1 + 20 else v1 end) = 2";
|
||||
String plan = getFragmentPlan(sql);
|
||||
assertContains(plan, " 0:OlapScanNode\n" +
|
||||
" TABLE: t0\n" +
|
||||
" PREAGGREGATION: ON\n" +
|
||||
" PREDICATES: CASE WHEN 1: v1 > 1 THEN 1: v1 + 10 WHEN 1: v1 > 2 THEN 1: v1 + 20 ELSE 1: v1 END = 2");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -613,11 +613,8 @@ class SelectStmtWithCaseWhenTest {
|
|||
} else {
|
||||
Assertions.assertTrue(patterns.stream().anyMatch(plan::contains), joiner.toString());
|
||||
}
|
||||
starRocksAssert.getCtx().getSessionVariable().setEnablePredicateExprReuse(true);
|
||||
|
||||
// String code = "{\n\"" + sql.replace("\n", " ") + "\",\n" + Arrays.stream(plan.split("\n"))
|
||||
// .filter(c -> c.contains("PREDICATES:")).map(c -> c.replace("PREDICATES:", "").trim())
|
||||
// .collect(Collectors.joining(", ", "\"", "\"")) + "},";
|
||||
// System.out.println(code);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -639,6 +636,18 @@ class SelectStmtWithCaseWhenTest {
|
|||
"FROM cte01\n" +
|
||||
"WHERE len_bucket IS NOT NULL;";
|
||||
String plan = UtFrameUtils.getVerboseFragmentPlan(starRocksAssert.getCtx(), sql);
|
||||
Assert.assertTrue(plan.contains("CASE WHEN array_length"));
|
||||
Assert.assertTrue(plan.contains(" 2:SELECT\n" +
|
||||
" | predicates: 3: case IS NOT NULL\n" +
|
||||
" | cardinality: 1\n" +
|
||||
" | \n" +
|
||||
" 1:Project\n" +
|
||||
" | output columns:\n" +
|
||||
" | 1 <-> [1: id, VARCHAR, false]\n" +
|
||||
" | 3 <-> CASE WHEN [5: array_length, INT, true] < 2 THEN 'bucket1' " +
|
||||
"WHEN ([5: array_length, INT, true] >= 2) AND ([5: array_length, INT, true] < 4) THEN 'bucket2' ELSE NULL END\n" +
|
||||
" | 4 <-> [5: array_length, INT, true]\n" +
|
||||
" | common expressions:\n" +
|
||||
" | 5 <-> array_length[([2: col_arr, ARRAY<VARCHAR(100)>, true]); " +
|
||||
"args: INVALID_TYPE; result: INT; args nullable: true; result nullable: true]"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue