Skip to content

Commit

Permalink
planner: use ordered index with is null predicate (pingcap#54253)
Browse files Browse the repository at this point in the history
  • Loading branch information
ari-e authored Jul 19, 2024
1 parent c361587 commit 41ed0e5
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 19 deletions.
2 changes: 1 addition & 1 deletion pkg/planner/core/casetest/index/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ go_test(
],
data = glob(["testdata/**"]),
flaky = True,
shard_count = 5,
shard_count = 6,
deps = [
"//pkg/testkit",
"//pkg/testkit/testdata",
Expand Down
12 changes: 12 additions & 0 deletions pkg/planner/core/casetest/index/index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,15 @@ func TestRangeIntersection(t *testing.T) {
tk.MustQuery(sql).Sort().Check(testkit.Rows(output[i].Result...))
}
}

func TestOrderedIndexWithIsNull(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("CREATE TABLE t1 (a int key, b int, c int, index (b, c));")
tk.MustQuery("explain select a from t1 where b is null order by c").Check(testkit.Rows(
"Projection_6 10.00 root test.t1.a",
"└─IndexReader_12 10.00 root index:IndexRangeScan_11",
" └─IndexRangeScan_11 10.00 cop[tikv] table:t1, index:b(b, c) range:[NULL,NULL], keep order:true, stats:pseudo",
))
}
51 changes: 36 additions & 15 deletions pkg/util/ranger/detacher.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,16 @@ func getPotentialEqOrInColOffset(sctx *rangerctx.RangerContext, expr expression.
return i
}
}
case ast.IsNull:
c, ok := f.GetArgs()[0].(*expression.Column)
if !ok {
return -1
}
for i, col := range cols {
if col.EqualColumn(c) {
return i
}
}
}
return -1
}
Expand Down Expand Up @@ -635,27 +645,34 @@ func allEqOrIn(expr expression.Expression) bool {
}
}
return true
case ast.EQ, ast.NullEQ, ast.In:
case ast.EQ, ast.NullEQ, ast.In, ast.IsNull:
return true
}
return false
}

func extractValueInfo(expr expression.Expression) *valueInfo {
if f, ok := expr.(*expression.ScalarFunction); ok && (f.FuncName.L == ast.EQ || f.FuncName.L == ast.NullEQ) {
getValueInfo := func(c *expression.Constant) *valueInfo {
mutable := c.ParamMarker != nil || c.DeferredExpr != nil
var value *types.Datum
if !mutable {
value = &c.Value
if f, ok := expr.(*expression.ScalarFunction); ok {
if f.FuncName.L == ast.IsNull {
val := &types.Datum{}
val.SetNull()
return &valueInfo{value: val, mutable: false}
}
if f.FuncName.L == ast.EQ || f.FuncName.L == ast.NullEQ {
getValueInfo := func(c *expression.Constant) *valueInfo {
mutable := c.ParamMarker != nil || c.DeferredExpr != nil
var value *types.Datum
if !mutable {
value = &c.Value
}
return &valueInfo{value, mutable}
}
if c, ok := f.GetArgs()[0].(*expression.Constant); ok {
return getValueInfo(c)
}
if c, ok := f.GetArgs()[1].(*expression.Constant); ok {
return getValueInfo(c)
}
return &valueInfo{value, mutable}
}
if c, ok := f.GetArgs()[0].(*expression.Constant); ok {
return getValueInfo(c)
}
if c, ok := f.GetArgs()[1].(*expression.Constant); ok {
return getValueInfo(c)
}
}
return nil
Expand Down Expand Up @@ -714,8 +731,12 @@ func ExtractEqAndInCondition(sctx *rangerctx.RangerContext, conditions []express
if ma == nil {
if accesses[i] != nil {
if allEqOrIn(accesses[i]) {
newConditions = append(newConditions, accesses[i])
columnValues[i] = extractValueInfo(accesses[i])
if columnValues[i] != nil && columnValues[i].value != nil && columnValues[i].value.IsNull() {
accesses[i] = nil
} else {
newConditions = append(newConditions, accesses[i])
}
} else {
accesses[i] = nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,13 @@ explain format = 'brief' select * from t3 where a >= 'a' and a <= 'a' and b = 'b
id estRows task access object operator info
IndexReader 0.33 root index:IndexRangeScan
└─IndexRangeScan 0.33 cop[tikv] table:t3, index:a(a, b, c) range:("a" "b" "c","a" "b" +inf], keep order:false, stats:pseudo
explain format = 'brief' select * from t1 where a is null or a in (1, 2, 3);
id estRows task access object operator info
IndexReader 260.00 root index:IndexRangeScan
└─IndexRangeScan 260.00 cop[tikv] table:t1, index:a(a, b, c) range:[NULL,NULL], [1,3], keep order:false, stats:pseudo
explain format = 'brief' select * from t1 where a is null and a = 1;
id estRows task access object operator info
TableDual 0.00 root rows:0
drop table if exists t1;
CREATE TABLE t1 (
key1 int(11) NOT NULL,
Expand Down
5 changes: 2 additions & 3 deletions tests/integrationtest/r/util/ranger.result
Original file line number Diff line number Diff line change
Expand Up @@ -482,9 +482,8 @@ a b c
1 2 2
explain format='brief' select * from t where a = 1 and (b is null or b = 2) and c > 1;
id estRows task access object operator info
IndexReader 0.07 root index:Selection
└─Selection 0.07 cop[tikv] gt(util__ranger.t.c, 1)
└─IndexRangeScan 0.20 cop[tikv] table:t, index:a(a, b, c) range:[1 NULL,1 NULL], [1 2,1 2], keep order:false, stats:pseudo
IndexReader 0.67 root index:IndexRangeScan
└─IndexRangeScan 0.67 cop[tikv] table:t, index:a(a, b, c) range:(1 NULL 1,1 NULL +inf], (1 2 1,1 2 +inf], keep order:false, stats:pseudo
select * from t where a = 1 and (b is null or b = 2) and c > 1;
a b c
1 2 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ explain format = 'brief' select * from t0 where a > 1 and a < 3 order by b limit
explain format = 'brief' select * from t1 where a >= 2 and a <= 2 and b = 2 and c > 2;
explain format = 'brief' select * from t2 where a >= 2.5 and a <= 2.5 order by b limit 2;
explain format = 'brief' select * from t3 where a >= 'a' and a <= 'a' and b = 'b' and c > 'c';
explain format = 'brief' select * from t1 where a is null or a in (1, 2, 3);
explain format = 'brief' select * from t1 where a is null and a = 1;

# TestIssue22105
drop table if exists t1;
Expand Down

0 comments on commit 41ed0e5

Please sign in to comment.