diff --git a/cmd/explaintest/r/select.result b/cmd/explaintest/r/select.result index bce3ecf8ba436..573fa51565556 100644 --- a/cmd/explaintest/r/select.result +++ b/cmd/explaintest/r/select.result @@ -432,3 +432,36 @@ Projection_7 10000.00 root 6_aux_0 │ └─TableScan_9 10000.00 cop table:t1, range:[-inf,+inf], keep order:false, stats:pseudo └─TableReader_12 10000.00 root data:TableScan_11 └─TableScan_11 10000.00 cop table:t2, range:[-inf,+inf], keep order:false, stats:pseudo +drop table if exists t; +create table t(a int, b int); +explain select a from t order by rand(); +id count task operator info +Projection_8 10000.00 root test.t.a +└─Sort_4 10000.00 root col_1:asc + └─Projection_9 10000.00 root test.t.a, rand() + └─TableReader_7 10000.00 root data:TableScan_6 + └─TableScan_6 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo +explain select a, b from t order by abs(2); +id count task operator info +TableReader_8 10000.00 root data:TableScan_7 +└─TableScan_7 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo +explain select a from t order by abs(rand())+1; +id count task operator info +Projection_8 10000.00 root test.t.a +└─Sort_4 10000.00 root col_1:asc + └─Projection_9 10000.00 root test.t.a, plus(abs(rand()), 1) + └─TableReader_7 10000.00 root data:TableScan_6 + └─TableScan_6 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo +drop table if exists t1; +create table t1(a int, b int); +drop table if exists t2; +create table t2(a int, b int); +explain select * from t1 where t1.a in (select t2.a as a from t2 where t2.b > t1.b order by t1.b); +id count task operator info +Apply_11 9990.00 root semi join, inner:TableReader_19, equal:[eq(test.t1.a, test.t2.a)] +├─TableReader_14 9990.00 root data:Selection_13 +│ └─Selection_13 9990.00 cop not(isnull(test.t1.a)) +│ └─TableScan_12 10000.00 cop table:t1, range:[-inf,+inf], keep order:false, stats:pseudo +└─TableReader_19 7992.00 root data:Selection_18 + └─Selection_18 7992.00 cop gt(test.t2.b, test.t1.b), not(isnull(test.t2.a)) + └─TableScan_17 10000.00 cop table:t2, range:[-inf,+inf], keep order:false, stats:pseudo diff --git a/cmd/explaintest/t/select.test b/cmd/explaintest/t/select.test index a5b04f20f463b..3f3fb13d71031 100644 --- a/cmd/explaintest/t/select.test +++ b/cmd/explaintest/t/select.test @@ -203,3 +203,17 @@ explain select a in (select a+b from t t2 where t2.b = t1.b) from t t1; drop table t; create table t(a int not null, b int); explain select a in (select a from t t2 where t2.b = t1.b) from t t1; + +# test order by rand() +drop table if exists t; +create table t(a int, b int); +explain select a from t order by rand(); +explain select a, b from t order by abs(2); +explain select a from t order by abs(rand())+1; + +# test order by correlated column +drop table if exists t1; +create table t1(a int, b int); +drop table if exists t2; +create table t2(a int, b int); +explain select * from t1 where t1.a in (select t2.a as a from t2 where t2.b > t1.b order by t1.b); diff --git a/executor/sort_test.go b/executor/sort_test.go deleted file mode 100644 index 3cc18f5953c8f..0000000000000 --- a/executor/sort_test.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2019 PingCAP, Inc. -// -// Licensed 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, -// See the License for the specific language governing permissions and -// limitations under the License. - -package executor_test - -import ( - . "github.com/pingcap/check" - "github.com/pingcap/tidb/util/testkit" -) - -func (s *testSuite4) TestSortRand(c *C) { - tk := testkit.NewTestKit(c, s.store) - tk.MustExec("use test") - tk.MustExec("drop table if exists t") - tk.MustExec("create table t(a int, b int);") - - tk.MustQuery("explain select a from t order by rand()").Check(testkit.Rows( - "Projection_8 10000.00 root test.t.a", - "└─Sort_4 10000.00 root col_1:asc", - " └─Projection_9 10000.00 root test.t.a, rand()", - " └─TableReader_7 10000.00 root data:TableScan_6", - " └─TableScan_6 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo", - )) - - tk.MustQuery("explain select a, b from t order by abs(2)").Check(testkit.Rows( - "TableReader_8 10000.00 root data:TableScan_7", - "└─TableScan_7 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo")) - - tk.MustQuery("explain select a from t order by abs(rand())+1").Check(testkit.Rows( - "Projection_8 10000.00 root test.t.a", - "└─Sort_4 10000.00 root col_1:asc", - " └─Projection_9 10000.00 root test.t.a, plus(abs(rand()), 1)", - " └─TableReader_7 10000.00 root data:TableScan_6", - " └─TableScan_6 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo", - )) -} diff --git a/expression/column.go b/expression/column.go index c76db51d924ed..055f22207c688 100644 --- a/expression/column.go +++ b/expression/column.go @@ -160,7 +160,7 @@ func (col *CorrelatedColumn) IsCorrelated() bool { // ConstItem implements Expression interface. func (col *CorrelatedColumn) ConstItem() bool { - return true + return false } // Decorrelate implements Expression interface. diff --git a/expression/column_test.go b/expression/column_test.go index e821ef1fd96a4..66aaec0e5f2f0 100644 --- a/expression/column_test.go +++ b/expression/column_test.go @@ -46,7 +46,7 @@ func (s *testEvaluatorSuite) TestColumn(c *C) { c.Assert(corCol.Equal(nil, corCol), IsTrue) c.Assert(corCol.Equal(nil, invalidCorCol), IsFalse) c.Assert(corCol.IsCorrelated(), IsTrue) - c.Assert(corCol.ConstItem(), IsTrue) + c.Assert(corCol.ConstItem(), IsFalse) c.Assert(corCol.Decorrelate(schema).Equal(nil, col), IsTrue) c.Assert(invalidCorCol.Decorrelate(schema).Equal(nil, invalidCorCol), IsTrue) diff --git a/expression/expression.go b/expression/expression.go index 7ce4bd835fdd4..bbada8e5dda08 100644 --- a/expression/expression.go +++ b/expression/expression.go @@ -108,6 +108,7 @@ type Expression interface { IsCorrelated() bool // ConstItem checks if this expression is constant item, regardless of query evaluation state. + // A constant item can be eval() when build a plan. // An expression is constant item if it: // refers no tables. // refers no subqueries that refers any tables. diff --git a/expression/util.go b/expression/util.go index 14a6cc94122fb..8db743abf3f30 100644 --- a/expression/util.go +++ b/expression/util.go @@ -632,22 +632,22 @@ func BuildNotNullExpr(ctx sessionctx.Context, expr Expression) Expression { return notNull } -// isMutableEffectsExpr checks if expr contains function which is mutable or has side effects. -func isMutableEffectsExpr(expr Expression) bool { +// IsMutableEffectsExpr checks if expr contains function which is mutable or has side effects. +func IsMutableEffectsExpr(expr Expression) bool { switch x := expr.(type) { case *ScalarFunction: if _, ok := mutableEffectsFunctions[x.FuncName.L]; ok { return true } for _, arg := range x.GetArgs() { - if isMutableEffectsExpr(arg) { + if IsMutableEffectsExpr(arg) { return true } } case *Column: case *Constant: if x.DeferredExpr != nil { - return isMutableEffectsExpr(x.DeferredExpr) + return IsMutableEffectsExpr(x.DeferredExpr) } } return false @@ -661,7 +661,7 @@ func RemoveDupExprs(ctx sessionctx.Context, exprs []Expression) []Expression { sc := ctx.GetSessionVars().StmtCtx for _, expr := range exprs { key := string(expr.HashCode(sc)) - if _, ok := exists[key]; !ok || isMutableEffectsExpr(expr) { + if _, ok := exists[key]; !ok || IsMutableEffectsExpr(expr) { res = append(res, expr) exists[key] = struct{}{} } diff --git a/planner/core/rule_column_pruning.go b/planner/core/rule_column_pruning.go index 2d8d3cfaf6073..c0b3bbda3bccd 100644 --- a/planner/core/rule_column_pruning.go +++ b/planner/core/rule_column_pruning.go @@ -149,12 +149,14 @@ func (la *LogicalAggregation) PruneColumns(parentUsedCols []*expression.Column) } // PruneColumns implements LogicalPlan interface. +// If any expression can view as a constant in execution stage, such as correlated column, constant, +// we do prune them. Note that we can't prune the expressions contain non-deterministic functions, such as rand(). func (ls *LogicalSort) PruneColumns(parentUsedCols []*expression.Column) error { child := ls.children[0] for i := len(ls.ByItems) - 1; i >= 0; i-- { cols := expression.ExtractColumns(ls.ByItems[i].Expr) if len(cols) == 0 { - if !ls.ByItems[i].Expr.ConstItem() { + if expression.IsMutableEffectsExpr(ls.ByItems[i].Expr) { continue } ls.ByItems = append(ls.ByItems[:i], ls.ByItems[i+1:]...)