From b9f04e1c25a1dc18f1742cde9b26014e11ca7603 Mon Sep 17 00:00:00 2001 From: Zhou Kunqin <25057648+time-and-fate@users.noreply.github.com> Date: Thu, 30 Nov 2023 21:14:48 +0800 Subject: [PATCH] *: code preparations for supporting build range for like function on new collation columns (#48972) ref pingcap/tidb#48181 --- cmd/explaintest/r/explain_easy.result | 18 +- executor/point_get.go | 6 +- planner/core/point_get_plan.go | 15 +- .../r/planner/core/range_scan_for_like.result | 999 ++++++++++++++++++ .../t/planner/core/range_scan_for_like.test | 243 +++++ util/ranger/detacher.go | 12 +- util/ranger/points.go | 52 +- util/ranger/ranger.go | 58 +- util/ranger/ranger_test.go | 4 +- util/ranger/types.go | 2 +- 10 files changed, 1344 insertions(+), 65 deletions(-) create mode 100644 tests/integrationtest/r/planner/core/range_scan_for_like.result create mode 100644 tests/integrationtest/t/planner/core/range_scan_for_like.test diff --git a/cmd/explaintest/r/explain_easy.result b/cmd/explaintest/r/explain_easy.result index b737fada05f0e..d26e254419edc 100644 --- a/cmd/explaintest/r/explain_easy.result +++ b/cmd/explaintest/r/explain_easy.result @@ -60,7 +60,7 @@ explain format = 'brief' delete from t1 where t1.c2 = 1; id estRows task access object operator info Delete N/A root N/A └─SelectLock 10.00 root for update 0 - └─IndexLookUp 10.00 root + └─IndexLookUp 10.00 root ├─IndexRangeScan(Build) 10.00 cop[tikv] table:t1, index:c2(c2) range:[1,1], keep order:false, stats:pseudo └─TableRowIDScan(Probe) 10.00 cop[tikv] table:t1 keep order:false, stats:pseudo explain format = 'brief' select count(b.c2) from t1 a, t2 b where a.c1 = b.c2 group by a.c1; @@ -174,11 +174,11 @@ Union 26000.00 root │ └─Union 16000.00 root │ ├─StreamAgg 8000.00 root group by:test.t2.c1, funcs:firstrow(test.t2.c1)->Column#12, funcs:firstrow(test.t2.c1)->Column#10 │ │ └─IndexReader 8000.00 root index:StreamAgg -│ │ └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, +│ │ └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, │ │ └─IndexFullScan 10000.00 cop[tikv] table:t2, index:c1(c1) keep order:true, stats:pseudo │ └─StreamAgg 8000.00 root group by:test.t2.c1, funcs:firstrow(test.t2.c1)->Column#12, funcs:firstrow(test.t2.c1)->Column#10 │ └─IndexReader 8000.00 root index:StreamAgg -│ └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, +│ └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, │ └─IndexFullScan 10000.00 cop[tikv] table:t2, index:c1(c1) keep order:true, stats:pseudo └─IndexReader 10000.00 root index:IndexFullScan └─IndexFullScan 10000.00 cop[tikv] table:t2, index:c1(c1) keep order:false, stats:pseudo @@ -188,15 +188,15 @@ HashAgg 24000.00 root group by:Column#10, funcs:firstrow(Column#11)->Column#10 └─Union 24000.00 root ├─StreamAgg 8000.00 root group by:test.t2.c1, funcs:firstrow(test.t2.c1)->Column#11, funcs:firstrow(test.t2.c1)->Column#10 │ └─IndexReader 8000.00 root index:StreamAgg - │ └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, + │ └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, │ └─IndexFullScan 10000.00 cop[tikv] table:t2, index:c1(c1) keep order:true, stats:pseudo ├─StreamAgg 8000.00 root group by:test.t2.c1, funcs:firstrow(test.t2.c1)->Column#11, funcs:firstrow(test.t2.c1)->Column#10 │ └─IndexReader 8000.00 root index:StreamAgg - │ └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, + │ └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, │ └─IndexFullScan 10000.00 cop[tikv] table:t2, index:c1(c1) keep order:true, stats:pseudo └─StreamAgg 8000.00 root group by:test.t2.c1, funcs:firstrow(test.t2.c1)->Column#11, funcs:firstrow(test.t2.c1)->Column#10 └─IndexReader 8000.00 root index:StreamAgg - └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, + └─StreamAgg 8000.00 cop[tikv] group by:test.t2.c1, └─IndexFullScan 10000.00 cop[tikv] table:t2, index:c1(c1) keep order:true, stats:pseudo select * from information_schema.tidb_indexes where table_name='t4'; TABLE_SCHEMA TABLE_NAME NON_UNIQUE KEY_NAME SEQ_IN_INDEX COLUMN_NAME SUB_PART INDEX_COMMENT Expression INDEX_ID IS_VISIBLE CLUSTERED @@ -797,14 +797,14 @@ create table t(a binary(16) not null, b varchar(2) default null, c varchar(100) explain format = 'brief' select * from t where a=x'FA34E1093CB428485734E3917F000000' and b='xb'; id estRows task access object operator info IndexLookUp 0.10 root -├─IndexRangeScan(Build) 0.10 cop[tikv] table:t, index:a(a, b) range:[0xFA34E1093CB428485734E3917F000000 "xb",0xFA34E1093CB428485734E3917F000000 "xb"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 0.10 cop[tikv] table:t, index:a(a, b) range:["\xfa4\xe1\t<\xb4(HW4\xe3\x91\x7f\x00\x00\x00" "xb","\xfa4\xe1\t<\xb4(HW4\xe3\x91\x7f\x00\x00\x00" "xb"], keep order:false, stats:pseudo └─TableRowIDScan(Probe) 0.10 cop[tikv] table:t keep order:false, stats:pseudo explain format = 'brief' update t set c = 'ssss' where a=x'FA34E1093CB428485734E3917F000000' and b='xb'; id estRows task access object operator info Update N/A root N/A └─SelectLock 0.10 root for update 0 - └─IndexLookUp 0.10 root - ├─IndexRangeScan(Build) 0.10 cop[tikv] table:t, index:a(a, b) range:[0xFA34E1093CB428485734E3917F000000 "xb",0xFA34E1093CB428485734E3917F000000 "xb"], keep order:false, stats:pseudo + └─IndexLookUp 0.10 root + ├─IndexRangeScan(Build) 0.10 cop[tikv] table:t, index:a(a, b) range:["\xfa4\xe1\t<\xb4(HW4\xe3\x91\x7f\x00\x00\x00" "xb","\xfa4\xe1\t<\xb4(HW4\xe3\x91\x7f\x00\x00\x00" "xb"], keep order:false, stats:pseudo └─TableRowIDScan(Probe) 0.10 cop[tikv] table:t keep order:false, stats:pseudo drop table if exists t; create table t(a int, b int); diff --git a/executor/point_get.go b/executor/point_get.go index 55062cda824e8..985b8501a3a68 100644 --- a/executor/point_get.go +++ b/executor/point_get.go @@ -540,11 +540,13 @@ func EncodeUniqueIndexValuesForKey(ctx sessionctx.Context, tblInfo *model.TableI colInfo := tblInfo.Columns[idxInfo.Columns[i].Offset] // table.CastValue will append 0x0 if the string value's length is smaller than the BINARY column's length. // So we don't use CastValue for string value for now. - // TODO: merge two if branch. + // TODO: The first if branch should have been removed, because the functionality of set the collation of the datum + // have been moved to util/ranger (normal path) and getNameValuePairs/getPointGetValue (fast path). But this change + // will be cherry-picked to a hotfix, so we choose to be a bit conservative and keep this for now. if colInfo.GetType() == mysql.TypeString || colInfo.GetType() == mysql.TypeVarString || colInfo.GetType() == mysql.TypeVarchar { var str string str, err = idxVals[i].ToString() - idxVals[i].SetString(str, colInfo.FieldType.GetCollate()) + idxVals[i].SetString(str, idxVals[i].Collation()) } else if colInfo.GetType() == mysql.TypeEnum && (idxVals[i].Kind() == types.KindString || idxVals[i].Kind() == types.KindBytes || idxVals[i].Kind() == types.KindBinaryLiteral) { var str string var e types.Enum diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index 43241b68fde7a..b9678b70040b9 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -1434,7 +1434,15 @@ func getNameValuePairs(ctx sessionctx.Context, tbl *model.TableInfo, tblName mod col := model.FindColumnInfo(tbl.Cols(), colName.Name.Name.L) if col == nil { // Handling the case when the column is _tidb_rowid. return append(nvPairs, nameValuePair{colName: colName.Name.Name.L, colFieldType: types.NewFieldType(mysql.TypeLonglong), value: d, con: con}), false - } else if col.GetType() == mysql.TypeString && col.GetCollate() == charset.CollationBin { // This type we needn't to pad `\0` in here. + } + + // As in buildFromBinOp in util/ranger, when we build key from the expression to do range scan or point get on + // a string column, we should set the collation of the string datum to collation of the column. + if col.FieldType.EvalType() == types.ETString && (d.Kind() == types.KindString || d.Kind() == types.KindBinaryLiteral) { + d.SetString(d.GetString(), col.FieldType.GetCollate()) + } + + if col.GetType() == mysql.TypeString && col.GetCollate() == charset.CollationBin { // This type we needn't to pad `\0` in here. return append(nvPairs, nameValuePair{colName: colName.Name.Name.L, colFieldType: &col.FieldType, value: d, con: con}), false } if !checkCanConvertInPointGet(col, d) { @@ -1464,6 +1472,11 @@ func getPointGetValue(stmtCtx *stmtctx.StatementContext, col *model.ColumnInfo, if !checkCanConvertInPointGet(col, *d) { return nil } + // As in buildFromBinOp in util/ranger, when we build key from the expression to do range scan or point get on + // a string column, we should set the collation of the string datum to collation of the column. + if col.FieldType.EvalType() == types.ETString && (d.Kind() == types.KindString || d.Kind() == types.KindBinaryLiteral) { + d.SetString(d.GetString(), col.FieldType.GetCollate()) + } dVal, err := d.ConvertTo(stmtCtx, &col.FieldType) if err != nil { return nil diff --git a/tests/integrationtest/r/planner/core/range_scan_for_like.result b/tests/integrationtest/r/planner/core/range_scan_for_like.result new file mode 100644 index 0000000000000..7dfdb7e8fb116 --- /dev/null +++ b/tests/integrationtest/r/planner/core/range_scan_for_like.result @@ -0,0 +1,999 @@ +create table t(a varchar(20) collate utf8mb4_general_ci, index ia(a)); +insert into t value('测试'),('测试Abc'),('测试 '),('你好'),('aABBccdd'),('Aa'),(''),(' '),(' '),(' 语言'),(' 语 言 '),('测测试 '),('测测试 '),(NULL); +explain select *, length(a) from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +a length(a) +测试 6 +测试 11 +测试Abc 9 +explain select *, length(a) from t use index (ia) where a like '测%%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测%%", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like '测%%' order by a,_tidb_rowid; +a length(a) +测测试 10 +测测试 13 +测试 6 +测试 11 +测试Abc 9 +explain select *, length(a) from t use index (ia) where a like '测%%试' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测%%试", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like '测%%试' order by a,_tidb_rowid; +a length(a) +测试 6 +explain select *, length(a) from t use index (ia) where a like '测试%%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%%", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like '测试%%' order by a,_tidb_rowid; +a length(a) +测试 6 +测试 11 +测试Abc 9 +explain select *, length(a) from t use index (ia) where a like '测试_' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试_", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like '测试_' order by a,_tidb_rowid; +a length(a) +explain select *, length(a) from t use index (ia) where a like '你好%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "你好%", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like '你好%' order by a,_tidb_rowid; +a length(a) +你好 6 +explain select *, length(a) from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +a length(a) +Aa 2 +explain select *, length(a) from t use index (ia) where a like 'aa%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa%' order by a,_tidb_rowid; +a length(a) +Aa 2 +aABBccdd 8 +explain select *, length(a) from t use index (ia) where a like 'aa%cc' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%cc", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa%cc' order by a,_tidb_rowid; +a length(a) +explain select *, length(a) from t use index (ia) where a like '' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like '' order by a,_tidb_rowid; +a length(a) + 0 +explain select *, length(a) from t use index (ia) where a like ' ' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " ", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like ' ' order by a,_tidb_rowid; +a length(a) + 1 +explain select *, length(a) from t use index (ia) where a like 'aa%dd' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%dd", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa%dd' order by a,_tidb_rowid; +a length(a) +aABBccdd 8 +explain select *, length(a) from t use index (ia) where a like 'aa%%dd' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%%dd", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa%%dd' order by a,_tidb_rowid; +a length(a) +aABBccdd 8 +explain select *, length(a) from t use index (ia) where a like 'aa_bccdd' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa_bccdd", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa_bccdd' order by a,_tidb_rowid; +a length(a) +aABBccdd 8 +explain select *, length(a) from t use index (ia) where a like '%%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "%%", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like '%%' order by a,_tidb_rowid; +a length(a) + 0 + 1 + 2 + 语 言 10 + 语言 7 +Aa 2 +aABBccdd 8 +你好 6 +测测试 10 +测测试 13 +测试 6 +测试 11 +测试Abc 9 +explain select *, length(a) from t use index (ia) where a like ' %%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %%", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like ' %%' order by a,_tidb_rowid; +a length(a) + 1 + 2 + 语 言 10 + 语言 7 +explain select *, length(a) from t use index (ia) where a like ' %%语言' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %%语言", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like ' %%语言' order by a,_tidb_rowid; +a length(a) + 语言 7 +explain select *, length(a) from t use index (ia) where a like ' 语 %' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 %", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like ' 语 %' order by a,_tidb_rowid; +a length(a) + 语 言 10 +explain select *, length(a) from t use index (ia) where a like ' 语 _' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_16 8000.00 root index:Selection_15 + └─Selection_15 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 _", 92) + └─IndexFullScan_14 10000.00 cop[tikv] table:t, index:ia(a) keep order:true, stats:pseudo +select *, length(a) from t use index (ia) where a like ' 语 _' order by a,_tidb_rowid; +a length(a) +drop table t; +create table t(a varchar(20) collate utf8mb4_unicode_ci, unique index ia(a)); +insert into t value(''),('测试'),('测试abc'),('你好'),('aabbccdd'),(' 语言'),(' 语 言 '),('测测试 '); +explain select *, length(a) from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +a length(a) +测试 6 +测试abc 9 +explain select *, length(a) from t use index (ia) where a like '测%%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测%%", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like '测%%' order by a,_tidb_rowid; +a length(a) +测测试 13 +测试 6 +测试abc 9 +explain select *, length(a) from t use index (ia) where a like '测%%试' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测%%试", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like '测%%试' order by a,_tidb_rowid; +a length(a) +测试 6 +explain select *, length(a) from t use index (ia) where a like '测试%%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%%", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like '测试%%' order by a,_tidb_rowid; +a length(a) +测试 6 +测试abc 9 +explain select *, length(a) from t use index (ia) where a like '测试_' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试_", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like '测试_' order by a,_tidb_rowid; +a length(a) +explain select *, length(a) from t use index (ia) where a like '你好%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "你好%", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like '你好%' order by a,_tidb_rowid; +a length(a) +你好 6 +explain select *, length(a) from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +a length(a) +explain select *, length(a) from t use index (ia) where a like 'aa%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa%' order by a,_tidb_rowid; +a length(a) +aabbccdd 8 +explain select *, length(a) from t use index (ia) where a like 'aa%cc' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%cc", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa%cc' order by a,_tidb_rowid; +a length(a) +explain select *, length(a) from t use index (ia) where a like '' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like '' order by a,_tidb_rowid; +a length(a) + 0 +explain select *, length(a) from t use index (ia) where a like 'aa%dd' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%dd", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa%dd' order by a,_tidb_rowid; +a length(a) +aabbccdd 8 +explain select *, length(a) from t use index (ia) where a like 'aa%%dd' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%%dd", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa%%dd' order by a,_tidb_rowid; +a length(a) +aabbccdd 8 +explain select *, length(a) from t use index (ia) where a like 'aa_bccdd' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa_bccdd", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like 'aa_bccdd' order by a,_tidb_rowid; +a length(a) +aabbccdd 8 +explain select *, length(a) from t use index (ia) where a like '%%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "%%", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like '%%' order by a,_tidb_rowid; +a length(a) + 0 + 语 言 10 + 语言 7 +aabbccdd 8 +你好 6 +测测试 13 +测试 6 +测试abc 9 +explain select *, length(a) from t use index (ia) where a like ' %%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %%", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like ' %%' order by a,_tidb_rowid; +a length(a) + 语 言 10 + 语言 7 +explain select *, length(a) from t use index (ia) where a like ' %%语言' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %%语言", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like ' %%语言' order by a,_tidb_rowid; +a length(a) + 语言 7 +explain select *, length(a) from t use index (ia) where a like ' 语 %' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 %", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like ' 语 %' order by a,_tidb_rowid; +a length(a) + 语 言 10 +explain select *, length(a) from t use index (ia) where a like ' 语 _' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 8000.00 root planner__core__range_scan_for_like.t.a, length(planner__core__range_scan_for_like.t.a)->Column#3, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexReader_12 8000.00 root index:Selection_11 + └─Selection_11 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 _", 92) + └─IndexFullScan_10 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo +select *, length(a) from t use index (ia) where a like ' 语 _' order by a,_tidb_rowid; +a length(a) +drop table t; +create table t(a varchar(20) collate utf8mb4_0900_ai_ci, b varchar(20) collate ascii_bin, c bigint, primary key(a(1), b) clustered); +insert into t (a, b, c) values +('测试1', 'asdfgh', 345346), +('你好2', 'qqwweerrrr', 987765), +('こんにちは3', 'zxcvbnn', 1111111), +('안녕하세요4', 'asdfgh ', 3333333333), +('Ciao5', ' asdfgh', 444400), +('Hola6', ' asdfgh ', 6666), +('Bonjour ', '', 888888888), +('Olá8', ' ', 9999999), +('Привет9', ' ', 321321), +('Hallo10', '12345', 35678); +explain select * from t use index (primary) where a like '测试%' and b like 'asd%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 200.00 root data:Selection_9 + └─Selection_9 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%", 92), like(planner__core__range_scan_for_like.t.b, "asd%", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like '测试%' and b like 'asd%' order by a,b; +a b c +测试1 asdfgh 345346 +explain select * from t use index (primary) where a like '测试1' and b like 'asdfgh %' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 200.00 root data:Selection_9 + └─Selection_9 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试1", 92), like(planner__core__range_scan_for_like.t.b, "asdfgh %", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like '测试1' and b like 'asdfgh %' order by a,b; +a b c +explain select * from t use index (primary) where a like 'こんにち_' and b like 'zxc%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 200.00 root data:Selection_9 + └─Selection_9 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "こんにち_", 92), like(planner__core__range_scan_for_like.t.b, "zxc%", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'こんにち_' and b like 'zxc%' order by a,b; +a b c +explain select * from t use index (primary) where a like '안녕하세요%' and b like 'asd%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 200.00 root data:Selection_9 + └─Selection_9 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "안녕하세요%", 92), like(planner__core__range_scan_for_like.t.b, "asd%", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like '안녕하세요%' and b like 'asd%' order by a,b; +a b c +안녕하세요4 asdfgh 3333333333 +explain select * from t use index (primary) where a like 'Ciáo%' and b like ' _%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 200.00 root data:Selection_9 + └─Selection_9 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "Ciáo%", 92), like(planner__core__range_scan_for_like.t.b, " _%", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'Ciáo%' and b like ' _%' order by a,b; +a b c +Ciao5 asdfgh 444400 +explain select * from t use index (primary) where a like '%HoLa%' and b like ' asdfgh' order by a,b; +id estRows task access object operator info +Sort_5 8.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 8.00 root data:Selection_9 + └─Selection_9 8.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "%HoLa%", 92), like(planner__core__range_scan_for_like.t.b, " asdfgh", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like '%HoLa%' and b like ' asdfgh' order by a,b; +a b c +explain select * from t use index (primary) where a like 'bonjour _%' and b like '' order by a,b; +id estRows task access object operator info +Sort_5 8.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 8.00 root data:Selection_9 + └─Selection_9 8.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "bonjour _%", 92), like(planner__core__range_scan_for_like.t.b, "", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'bonjour _%' and b like '' order by a,b; +a b c +Bonjour 888888888 +explain select * from t use index (primary) where a like 'OLa%' and b like '_' order by a,b; +id estRows task access object operator info +Sort_5 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 8000.00 root data:Selection_9 + └─Selection_9 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "OLa%", 92), like(planner__core__range_scan_for_like.t.b, "_", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'OLa%' and b like '_' order by a,b; +a b c +Olá8 9999999 +explain select * from t use index (primary) where a like 'Приве__' and b like ' %' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 200.00 root data:Selection_9 + └─Selection_9 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "Приве__", 92), like(planner__core__range_scan_for_like.t.b, " %", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'Приве__' and b like ' %' order by a,b; +a b c +Привет9 321321 +explain select * from t use index (primary) where a like 'Hallo%' and b like '123%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 200.00 root data:Selection_9 + └─Selection_9 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "Hallo%", 92), like(planner__core__range_scan_for_like.t.b, "123%", 92) + └─TableFullScan_8 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'Hallo%' and b like '123%' order by a,b; +a b c +Hallo10 12345 35678 +drop table t; +create table t(a varchar(20) collate gbk_chinese_ci, b varchar(20) collate latin1_bin, c bigint, primary key(a, b(5)) nonclustered); +insert into t (a, b, c) values +('测试1', 'asdfgh', 345346), +('你好2', 'qqwweerrrr', 987765), +('zxcvbnn',0xE38193E38293E381ABE381A1E381AF33, 1111111), +('asdfgh ', 0xEC9588EB8595ED9598EC84B8EC9A9434, 3333333333), +('Ciao5', ' asdfgh', 444400), +(' asdfgh ', 'Hola6', 6666), +('Bonjour ', '', 888888888), +('Olá8', ' ', 9999999), +('Привет9', ' ', 321321), +(' ', '12345', 35678); +set names utf8mb4; +explain select * from t use index (primary) where a like '测试%' and b like 'asd%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 200.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, "asd%", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like '测试%' and b like 'asd%' order by a,b; +a b c +测试1 asdfgh 345346 +explain select * from t use index (primary) where a like '测试1' and b like 'asdfgh %' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 200.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试1", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, "asdfgh %", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like '测试1' and b like 'asdfgh %' order by a,b; +a b c +set names latin1; +explain select * from t use index (primary) where b like 'こんにち_' and a like 'zxc%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 200.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "zxc%", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, "こんにち_", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where b like 'こんにち_' and a like 'zxc%' order by a,b; +a b c +explain select * from t use index (primary) where b like '안녕하세요%' and a like 'asd%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 200.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "asd%", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, "안녕하세요%", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where b like '안녕하세요%' and a like 'asd%' order by a,b; +a b c +asdfgh 안녕하세요4 3333333333 +set names utf8mb4; +explain select * from t use index (primary) where a like 'Ciao%' and b like ' _%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 200.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "Ciao%", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, " _%", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'Ciao%' and b like ' _%' order by a,b; +a b c +Ciao5 asdfgh 444400 +explain select * from t use index (primary) where b like 'HoLa%' and a like ' asdfgh' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 200.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " asdfgh", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, "HoLa%", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where b like 'HoLa%' and a like ' asdfgh' order by a,b; +a b c +explain select * from t use index (primary) where a like 'bonjour _%' and b like '' order by a,b; +id estRows task access object operator info +Sort_5 8.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 8.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "bonjour _%", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 8.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, "", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'bonjour _%' and b like '' order by a,b; +a b c +Bonjour 888888888 +explain select * from t use index (primary) where a like 'OLá' and b like '_' order by a,b; +id estRows task access object operator info +Sort_5 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 8000.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "OLá", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, "_", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'OLá' and b like '_' order by a,b; +a b c +explain select * from t use index (primary) where a like 'Приве__' and b like ' %' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 200.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "Приве__", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, " %", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like 'Приве__' and b like ' %' order by a,b; +a b c +Привет9 321321 +explain select * from t use index (primary) where a like ' %' and b like '123%' order by a,b; +id estRows task access object operator info +Sort_5 200.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─IndexLookUp_12 200.00 root + ├─Selection_10(Build) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %", 92) + │ └─IndexFullScan_8 10000.00 cop[tikv] table:t, index:PRIMARY(a, b) keep order:false, stats:pseudo + └─Selection_11(Probe) 200.00 cop[tikv] like(planner__core__range_scan_for_like.t.b, "123%", 92) + └─TableRowIDScan_9 8000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (primary) where a like ' %' and b like '123%' order by a,b; +a b c + 12345 35678 +drop table t; +create table t(a varchar(20) collate utf8mb4_general_ci, b bigint, index ia(a(3))); +insert into t value +('测试',222), +('测试Abc',324), +('测试 ',543), +('你好',111), +('aABBccdd',890), +('A',456), +('Aa',456), +('aab',456), +('aabB',456), +('',234), +(' ',11111), +(' ',66666), +(' 语言',55555), +(' 语 言',3579), +('测测试 ',2468), +('测测试 ',99999), +(NULL,10); +explain select * from t use index (ia) where a > 'aabb' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 3333.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 3333.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 3333.33 root + ├─IndexRangeScan_9(Build) 3333.33 cop[tikv] table:t, index:ia(a) range:["aab",+inf], keep order:false, stats:pseudo + └─Selection_11(Probe) 3333.33 cop[tikv] gt(planner__core__range_scan_for_like.t.a, "aabb") + └─TableRowIDScan_10 3333.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a > 'aabb' order by a,_tidb_rowid; +a b +aABBccdd 890 +你好 111 +测测试 2468 +测测试 99999 +测试 222 +测试 543 +测试Abc 324 +explain select * from t use index (ia) where a > 'aab' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 3333.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 3333.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 3333.33 root + ├─IndexRangeScan_9(Build) 3333.33 cop[tikv] table:t, index:ia(a) range:["aab",+inf], keep order:false, stats:pseudo + └─Selection_11(Probe) 3333.33 cop[tikv] gt(planner__core__range_scan_for_like.t.a, "aab") + └─TableRowIDScan_10 3333.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a > 'aab' order by a,_tidb_rowid; +a b +aabB 456 +aABBccdd 890 +你好 111 +测测试 2468 +测测试 99999 +测试 222 +测试 543 +测试Abc 324 +explain select * from t use index (ia) where a > 'aa' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 3333.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 3333.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 3333.33 root + ├─IndexRangeScan_9(Build) 3333.33 cop[tikv] table:t, index:ia(a) range:("aa",+inf], keep order:false, stats:pseudo + └─Selection_11(Probe) 3333.33 cop[tikv] gt(planner__core__range_scan_for_like.t.a, "aa") + └─TableRowIDScan_10 3333.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a > 'aa' order by a,_tidb_rowid; +a b +aab 456 +aabB 456 +aABBccdd 890 +你好 111 +测测试 2468 +测测试 99999 +测试 222 +测试 543 +测试Abc 324 +explain select * from t use index (ia) where a < 'aabb' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 3323.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 3323.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 3323.33 root + ├─IndexRangeScan_9(Build) 3323.33 cop[tikv] table:t, index:ia(a) range:[-inf,"aab"], keep order:false, stats:pseudo + └─Selection_11(Probe) 3323.33 cop[tikv] lt(planner__core__range_scan_for_like.t.a, "aabb") + └─TableRowIDScan_10 3323.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a < 'aabb' order by a,_tidb_rowid; +a b + 234 + 11111 + 66666 + 语 言 3579 + 语言 55555 +A 456 +Aa 456 +aab 456 +explain select * from t use index (ia) where a < 'aab' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 3323.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 3323.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 3323.33 root + ├─IndexRangeScan_9(Build) 3323.33 cop[tikv] table:t, index:ia(a) range:[-inf,"aab"), keep order:false, stats:pseudo + └─Selection_11(Probe) 3323.33 cop[tikv] lt(planner__core__range_scan_for_like.t.a, "aab") + └─TableRowIDScan_10 3323.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a < 'aab' order by a,_tidb_rowid; +a b + 234 + 11111 + 66666 + 语 言 3579 + 语言 55555 +A 456 +Aa 456 +explain select * from t use index (ia) where a < 'aa' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 3323.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 3323.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 3323.33 root + ├─IndexRangeScan_9(Build) 3323.33 cop[tikv] table:t, index:ia(a) range:[-inf,"aa"), keep order:false, stats:pseudo + └─Selection_11(Probe) 3323.33 cop[tikv] lt(planner__core__range_scan_for_like.t.a, "aa") + └─TableRowIDScan_10 3323.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a < 'aa' order by a,_tidb_rowid; +a b + 234 + 11111 + 66666 + 语 言 3579 + 语言 55555 +A 456 +explain select * from t use index (ia) where a != 'aa' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 6656.67 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 6656.67 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 6656.67 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 6656.67 cop[tikv] ne(planner__core__range_scan_for_like.t.a, "aa") + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a != 'aa' order by a,_tidb_rowid; +a b + 234 + 11111 + 66666 + 语 言 3579 + 语言 55555 +A 456 +aab 456 +aabB 456 +aABBccdd 890 +你好 111 +测测试 2468 +测测试 99999 +测试 222 +测试 543 +测试Abc 324 +explain select * from t use index (ia) where a != 'aaBbc' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 6656.67 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 6656.67 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 6656.67 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 6656.67 cop[tikv] ne(planner__core__range_scan_for_like.t.a, "aaBbc") + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a != 'aaBbc' order by a,_tidb_rowid; +a b + 234 + 11111 + 66666 + 语 言 3579 + 语言 55555 +A 456 +Aa 456 +aab 456 +aabB 456 +aABBccdd 890 +你好 111 +测测试 2468 +测测试 99999 +测试 222 +测试 543 +测试Abc 324 +explain select * from t use index (ia) where a like '测试abc' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试abc", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like '测试abc' order by a,_tidb_rowid; +a b +测试Abc 324 +explain select * from t use index (ia) where a = '测试abc' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 10.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 10.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 10.00 root + ├─IndexRangeScan_9(Build) 10.00 cop[tikv] table:t, index:ia(a) range:["测试a","测试a"], keep order:false, stats:pseudo + └─Selection_11(Probe) 10.00 cop[tikv] eq(planner__core__range_scan_for_like.t.a, "测试abc") + └─TableRowIDScan_10 10.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a = '测试abc' order by a,_tidb_rowid; +a b +测试Abc 324 +explain select * from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +a b +Aa 456 +explain select * from t use index (ia) where a = 'aa' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 10.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 10.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 10.00 root + ├─IndexRangeScan_9(Build) 10.00 cop[tikv] table:t, index:ia(a) range:["aa","aa"], keep order:false, stats:pseudo + └─Selection_11(Probe) 10.00 cop[tikv] eq(planner__core__range_scan_for_like.t.a, "aa") + └─TableRowIDScan_10 10.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a = 'aa' order by a,_tidb_rowid; +a b +Aa 456 +explain select * from t use index (ia) where a like '测测试 ' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测测试 ", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like '测测试 ' order by a,_tidb_rowid; +a b +测测试 2468 +explain select * from t use index (ia) where a = '测测试 ' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 10.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 10.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 10.00 root + ├─IndexRangeScan_9(Build) 10.00 cop[tikv] table:t, index:ia(a) range:["测测试","测测试"], keep order:false, stats:pseudo + └─Selection_11(Probe) 10.00 cop[tikv] eq(planner__core__range_scan_for_like.t.a, "测测试 ") + └─TableRowIDScan_10 10.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a = '测测试 ' order by a,_tidb_rowid; +a b +测测试 2468 +测测试 99999 +explain select * from t use index (ia) where a like ' 语 言' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 言", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like ' 语 言' order by a,_tidb_rowid; +a b + 语 言 3579 +explain select * from t use index (ia) where a = ' 语 言' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 10.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 10.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 10.00 root + ├─IndexRangeScan_9(Build) 10.00 cop[tikv] table:t, index:ia(a) range:[" 语"," 语"], keep order:false, stats:pseudo + └─Selection_11(Probe) 10.00 cop[tikv] eq(planner__core__range_scan_for_like.t.a, " 语 言") + └─TableRowIDScan_10 10.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a = ' 语 言' order by a,_tidb_rowid; +a b + 语 言 3579 +explain select * from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +a b +测试 222 +测试 543 +测试Abc 324 +explain select * from t use index (ia) where a like '测_' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测_", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like '测_' order by a,_tidb_rowid; +a b +测试 222 +explain select * from t use index (ia) where a like '测测试 %' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测测试 %", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like '测测试 %' order by a,_tidb_rowid; +a b +测测试 2468 +测测试 99999 +explain select * from t use index (ia) where a like '测试a__' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试a__", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like '测试a__' order by a,_tidb_rowid; +a b +测试Abc 324 +explain select * from t use index (ia) where a like '测试 __' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试 __", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like '测试 __' order by a,_tidb_rowid; +a b +测试 543 +explain select * from t use index (ia) where a like ' _' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " _", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like ' _' order by a,_tidb_rowid; +a b +explain select * from t use index (ia) where a like ' %' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like ' %' order by a,_tidb_rowid; +a b + 66666 +explain select * from t use index (ia) where a like ' 语言%%' order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 8000.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 8000.00 root + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a) keep order:false, stats:pseudo + └─Selection_11(Probe) 8000.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语言%%", 92) + └─TableRowIDScan_10 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a like ' 语言%%' order by a,_tidb_rowid; +a b + 语言 55555 diff --git a/tests/integrationtest/t/planner/core/range_scan_for_like.test b/tests/integrationtest/t/planner/core/range_scan_for_like.test new file mode 100644 index 0000000000000..c6113bc053bfe --- /dev/null +++ b/tests/integrationtest/t/planner/core/range_scan_for_like.test @@ -0,0 +1,243 @@ +# Suite 1: utf8mb4_general_ci + normal index +create table t(a varchar(20) collate utf8mb4_general_ci, index ia(a)); +insert into t value('测试'),('测试Abc'),('测试 '),('你好'),('aABBccdd'),('Aa'),(''),(' '),(' '),(' 语言'),(' 语 言 '),('测测试 '),('测测试 '),(NULL); +# test cases for the pattern string cover: +# with/without wildcard +# start/end with wildcard +# [non-]ascii characters +# [only] contain empty string/space +explain select *, length(a) from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '测%%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测%%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '测%%试' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测%%试' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '测试%%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测试%%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '测试_' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测试_' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '你好%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '你好%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa%cc' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa%cc' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like ' ' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like ' ' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa%dd' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa%dd' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa%%dd' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa%%dd' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa_bccdd' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa_bccdd' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '%%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '%%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like ' %%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like ' %%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like ' %%语言' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like ' %%语言' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like ' 语 %' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like ' 语 %' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like ' 语 _' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like ' 语 _' order by a,_tidb_rowid; +drop table t; +# Suite 2: utf8mb4_unicode_ci + unique index +create table t(a varchar(20) collate utf8mb4_unicode_ci, unique index ia(a)); +insert into t value(''),('测试'),('测试abc'),('你好'),('aabbccdd'),(' 语言'),(' 语 言 '),('测测试 '); +# test cases for the pattern string are the same with Suite 1 +explain select *, length(a) from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '测%%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测%%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '测%%试' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测%%试' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '测试%%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测试%%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '测试_' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '测试_' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '你好%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '你好%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa%cc' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa%cc' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa%dd' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa%dd' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa%%dd' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa%%dd' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like 'aa_bccdd' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like 'aa_bccdd' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like '%%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like '%%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like ' %%' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like ' %%' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like ' %%语言' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like ' %%语言' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like ' 语 %' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like ' 语 %' order by a,_tidb_rowid; +explain select *, length(a) from t use index (ia) where a like ' 语 _' order by a,_tidb_rowid; +select *, length(a) from t use index (ia) where a like ' 语 _' order by a,_tidb_rowid; +drop table t; +# Suite 3: utf8mb4_0900_ai_ci + ascii_bin + multi-column index + prefix index + primary key (clustered) +create table t(a varchar(20) collate utf8mb4_0900_ai_ci, b varchar(20) collate ascii_bin, c bigint, primary key(a(1), b) clustered); +insert into t (a, b, c) values +('测试1', 'asdfgh', 345346), +('你好2', 'qqwweerrrr', 987765), +('こんにちは3', 'zxcvbnn', 1111111), +('안녕하세요4', 'asdfgh ', 3333333333), +('Ciao5', ' asdfgh', 444400), +('Hola6', ' asdfgh ', 6666), +('Bonjour ', '', 888888888), +('Olá8', ' ', 9999999), +('Привет9', ' ', 321321), +('Hallo10', '12345', 35678); +explain select * from t use index (primary) where a like '测试%' and b like 'asd%' order by a,b; +select * from t use index (primary) where a like '测试%' and b like 'asd%' order by a,b; +explain select * from t use index (primary) where a like '测试1' and b like 'asdfgh %' order by a,b; +select * from t use index (primary) where a like '测试1' and b like 'asdfgh %' order by a,b; +explain select * from t use index (primary) where a like 'こんにち_' and b like 'zxc%' order by a,b; +select * from t use index (primary) where a like 'こんにち_' and b like 'zxc%' order by a,b; +explain select * from t use index (primary) where a like '안녕하세요%' and b like 'asd%' order by a,b; +select * from t use index (primary) where a like '안녕하세요%' and b like 'asd%' order by a,b; +explain select * from t use index (primary) where a like 'Ciáo%' and b like ' _%' order by a,b; +select * from t use index (primary) where a like 'Ciáo%' and b like ' _%' order by a,b; +explain select * from t use index (primary) where a like '%HoLa%' and b like ' asdfgh' order by a,b; +select * from t use index (primary) where a like '%HoLa%' and b like ' asdfgh' order by a,b; +explain select * from t use index (primary) where a like 'bonjour _%' and b like '' order by a,b; +select * from t use index (primary) where a like 'bonjour _%' and b like '' order by a,b; +explain select * from t use index (primary) where a like 'OLa%' and b like '_' order by a,b; +select * from t use index (primary) where a like 'OLa%' and b like '_' order by a,b; +explain select * from t use index (primary) where a like 'Приве__' and b like ' %' order by a,b; +select * from t use index (primary) where a like 'Приве__' and b like ' %' order by a,b; +explain select * from t use index (primary) where a like 'Hallo%' and b like '123%' order by a,b; +select * from t use index (primary) where a like 'Hallo%' and b like '123%' order by a,b; +drop table t; +# Suite 4: gbk_chinese_ci + latin1_bin + multi-column index + prefix index + primary key (nonclustered) +create table t(a varchar(20) collate gbk_chinese_ci, b varchar(20) collate latin1_bin, c bigint, primary key(a, b(5)) nonclustered); +insert into t (a, b, c) values +('测试1', 'asdfgh', 345346), +('你好2', 'qqwweerrrr', 987765), +('zxcvbnn',0xE38193E38293E381ABE381A1E381AF33, 1111111), +('asdfgh ', 0xEC9588EB8595ED9598EC84B8EC9A9434, 3333333333), +('Ciao5', ' asdfgh', 444400), +(' asdfgh ', 'Hola6', 6666), +('Bonjour ', '', 888888888), +('Olá8', ' ', 9999999), +('Привет9', ' ', 321321), +(' ', '12345', 35678); +set names utf8mb4; +explain select * from t use index (primary) where a like '测试%' and b like 'asd%' order by a,b; +select * from t use index (primary) where a like '测试%' and b like 'asd%' order by a,b; +explain select * from t use index (primary) where a like '测试1' and b like 'asdfgh %' order by a,b; +select * from t use index (primary) where a like '测试1' and b like 'asdfgh %' order by a,b; +set names latin1; +explain select * from t use index (primary) where b like 'こんにち_' and a like 'zxc%' order by a,b; +select * from t use index (primary) where b like 'こんにち_' and a like 'zxc%' order by a,b; +explain select * from t use index (primary) where b like '안녕하세요%' and a like 'asd%' order by a,b; +select * from t use index (primary) where b like '안녕하세요%' and a like 'asd%' order by a,b; +set names utf8mb4; +explain select * from t use index (primary) where a like 'Ciao%' and b like ' _%' order by a,b; +select * from t use index (primary) where a like 'Ciao%' and b like ' _%' order by a,b; +explain select * from t use index (primary) where b like 'HoLa%' and a like ' asdfgh' order by a,b; +select * from t use index (primary) where b like 'HoLa%' and a like ' asdfgh' order by a,b; +explain select * from t use index (primary) where a like 'bonjour _%' and b like '' order by a,b; +select * from t use index (primary) where a like 'bonjour _%' and b like '' order by a,b; +explain select * from t use index (primary) where a like 'OLá' and b like '_' order by a,b; +select * from t use index (primary) where a like 'OLá' and b like '_' order by a,b; +explain select * from t use index (primary) where a like 'Приве__' and b like ' %' order by a,b; +select * from t use index (primary) where a like 'Приве__' and b like ' %' order by a,b; +explain select * from t use index (primary) where a like ' %' and b like '123%' order by a,b; +select * from t use index (primary) where a like ' %' and b like '123%' order by a,b; +drop table t; +# Suite 5: utf8mb4_general_ci + prefix index +create table t(a varchar(20) collate utf8mb4_general_ci, b bigint, index ia(a(3))); +insert into t value +('测试',222), +('测试Abc',324), +('测试 ',543), +('你好',111), +('aABBccdd',890), +('A',456), +('Aa',456), +('aab',456), +('aabB',456), +('',234), +(' ',11111), +(' ',66666), +(' 语言',55555), +(' 语 言',3579), +('测测试 ',2468), +('测测试 ',99999), +(NULL,10); +explain select * from t use index (ia) where a > 'aabb' order by a,_tidb_rowid; +select * from t use index (ia) where a > 'aabb' order by a,_tidb_rowid; +explain select * from t use index (ia) where a > 'aab' order by a,_tidb_rowid; +select * from t use index (ia) where a > 'aab' order by a,_tidb_rowid; +explain select * from t use index (ia) where a > 'aa' order by a,_tidb_rowid; +select * from t use index (ia) where a > 'aa' order by a,_tidb_rowid; +explain select * from t use index (ia) where a < 'aabb' order by a,_tidb_rowid; +select * from t use index (ia) where a < 'aabb' order by a,_tidb_rowid; +explain select * from t use index (ia) where a < 'aab' order by a,_tidb_rowid; +select * from t use index (ia) where a < 'aab' order by a,_tidb_rowid; +explain select * from t use index (ia) where a < 'aa' order by a,_tidb_rowid; +select * from t use index (ia) where a < 'aa' order by a,_tidb_rowid; +explain select * from t use index (ia) where a != 'aa' order by a,_tidb_rowid; +select * from t use index (ia) where a != 'aa' order by a,_tidb_rowid; +explain select * from t use index (ia) where a != 'aaBbc' order by a,_tidb_rowid; +select * from t use index (ia) where a != 'aaBbc' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like '测试abc' order by a,_tidb_rowid; +select * from t use index (ia) where a like '测试abc' order by a,_tidb_rowid; +explain select * from t use index (ia) where a = '测试abc' order by a,_tidb_rowid; +select * from t use index (ia) where a = '测试abc' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +select * from t use index (ia) where a like 'aa' order by a,_tidb_rowid; +explain select * from t use index (ia) where a = 'aa' order by a,_tidb_rowid; +select * from t use index (ia) where a = 'aa' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like '测测试 ' order by a,_tidb_rowid; +select * from t use index (ia) where a like '测测试 ' order by a,_tidb_rowid; +explain select * from t use index (ia) where a = '测测试 ' order by a,_tidb_rowid; +select * from t use index (ia) where a = '测测试 ' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like ' 语 言' order by a,_tidb_rowid; +select * from t use index (ia) where a like ' 语 言' order by a,_tidb_rowid; +explain select * from t use index (ia) where a = ' 语 言' order by a,_tidb_rowid; +select * from t use index (ia) where a = ' 语 言' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +select * from t use index (ia) where a like '测试%' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like '测_' order by a,_tidb_rowid; +select * from t use index (ia) where a like '测_' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like '测测试 %' order by a,_tidb_rowid; +select * from t use index (ia) where a like '测测试 %' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like '测试a__' order by a,_tidb_rowid; +select * from t use index (ia) where a like '测试a__' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like '测试 __' order by a,_tidb_rowid; +select * from t use index (ia) where a like '测试 __' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like ' _' order by a,_tidb_rowid; +select * from t use index (ia) where a like ' _' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like ' %' order by a,_tidb_rowid; +select * from t use index (ia) where a like ' %' order by a,_tidb_rowid; +explain select * from t use index (ia) where a like ' 语言%%' order by a,_tidb_rowid; +select * from t use index (ia) where a like ' 语言%%' order by a,_tidb_rowid; + + + + + + + + + + + + + + + + diff --git a/util/ranger/detacher.go b/util/ranger/detacher.go index 3c836d5a89fa1..ae9fff94e7db6 100644 --- a/util/ranger/detacher.go +++ b/util/ranger/detacher.go @@ -304,7 +304,7 @@ func unionColumnValues(lhs, rhs []*valueInfo) []*valueInfo { // detachCNFCondAndBuildRangeForIndex will detach the index filters from table filters. These conditions are connected with `and` // It will first find the point query column and then extract the range query column. // considerDNF is true means it will try to extract access conditions from the DNF expressions. -func (d *rangeDetacher) detachCNFCondAndBuildRangeForIndex(conditions []expression.Expression, tpSlice []*types.FieldType, considerDNF bool) (*DetachRangeResult, error) { +func (d *rangeDetacher) detachCNFCondAndBuildRangeForIndex(conditions []expression.Expression, newTpSlice []*types.FieldType, considerDNF bool) (*DetachRangeResult, error) { var ( eqCount int ranges Ranges @@ -317,7 +317,7 @@ func (d *rangeDetacher) detachCNFCondAndBuildRangeForIndex(conditions []expressi return res, nil } var remainedConds []expression.Expression - ranges, accessConds, remainedConds, err = d.buildRangeOnColsByCNFCond(tpSlice, len(accessConds), accessConds) + ranges, accessConds, remainedConds, err = d.buildRangeOnColsByCNFCond(newTpSlice, len(accessConds), accessConds) if err != nil { return nil, err } @@ -457,7 +457,7 @@ func (d *rangeDetacher) detachCNFCondAndBuildRangeForIndex(conditions []expressi } // `eqOrInCount` must be 0 when coming here. res.AccessConds, res.RemainedConds = detachColumnCNFConditions(d.sctx, newConditions, checker) - ranges, res.AccessConds, remainedConds, err = d.buildCNFIndexRange(tpSlice, 0, res.AccessConds) + ranges, res.AccessConds, remainedConds, err = d.buildCNFIndexRange(newTpSlice, 0, res.AccessConds) if err != nil { return nil, err } @@ -478,7 +478,7 @@ func (d *rangeDetacher) detachCNFCondAndBuildRangeForIndex(conditions []expressi accessConds = append(accessConds, cond) // TODO: if it's prefix column, we need to add cond to filterConds? } - ranges, accessConds, remainedConds, err = d.buildCNFIndexRange(tpSlice, eqOrInCount, accessConds) + ranges, accessConds, remainedConds, err = d.buildCNFIndexRange(newTpSlice, eqOrInCount, accessConds) if err != nil { return nil, err } @@ -613,7 +613,7 @@ func extractValueInfo(expr expression.Expression) *valueInfo { func ExtractEqAndInCondition(sctx sessionctx.Context, conditions []expression.Expression, cols []*expression.Column, lengths []int) ([]expression.Expression, []expression.Expression, []expression.Expression, []*valueInfo, bool) { var filters []expression.Expression - rb := builder{ctx: sctx} + rb := builder{sctx: sctx} accesses := make([]expression.Expression, len(cols)) points := make([][]*point, len(cols)) mergedAccesses := make([]expression.Expression, len(cols)) @@ -720,7 +720,7 @@ func (d *rangeDetacher) detachDNFCondAndBuildRangeForIndex(condition *expression length: d.lengths[0], optPrefixIndexSingleScan: d.sctx.GetSessionVars().OptPrefixIndexSingleScan, } - rb := builder{ctx: d.sctx} + rb := builder{sctx: d.sctx} dnfItems := expression.FlattenDNFConditions(condition) newAccessItems := make([]expression.Expression, 0, len(dnfItems)) var totalRanges Ranges diff --git a/util/ranger/points.go b/util/ranger/points.go index 0c646e8163dfa..ae77bfcf7e672 100644 --- a/util/ranger/points.go +++ b/util/ranger/points.go @@ -183,8 +183,8 @@ func NullRange() Ranges { // builder is the range builder struct. type builder struct { - err error - ctx sessionctx.Context + err error + sctx sessionctx.Context } // build converts Expression on one column into point, which can be further built into Range. @@ -193,7 +193,11 @@ type builder struct { // we pass it down from here. // If the input prefixLen is not types.UnspecifiedLength, it means it's for a prefix column in a prefix index. In such // cases, we should cut the prefix and adjust the exclusiveness. Ref: cutPrefixForPoints(). -func (r *builder) build(expr expression.Expression, collator collate.Collator, prefixLen int) []*point { +func (r *builder) build( + expr expression.Expression, + collator collate.Collator, + prefixLen int, +) []*point { switch x := expr.(type) { case *expression.Column: return r.buildFromColumn() @@ -216,7 +220,7 @@ func (r *builder) buildFromConstant(expr *expression.Constant) []*point { return nil } - val, err := dt.ToBool(r.ctx.GetSessionVars().StmtCtx) + val, err := dt.ToBool(r.sctx.GetSessionVars().StmtCtx) if err != nil { r.err = err return nil @@ -239,7 +243,10 @@ func (*builder) buildFromColumn() []*point { return []*point{startPoint1, endPoint1, startPoint2, endPoint2} } -func (r *builder) buildFromBinOp(expr *expression.ScalarFunction, prefixLen int) []*point { +func (r *builder) buildFromBinOp( + expr *expression.ScalarFunction, + prefixLen int, +) []*point { // This has been checked that the binary operation is comparison operation, and one of // the operand is column name expression. var ( @@ -261,11 +268,11 @@ func (r *builder) buildFromBinOp(expr *expression.ScalarFunction, prefixLen int) // If the original value is adjusted, we need to change the condition. // For example, col < 2156. Since the max year is 2155, 2156 is changed to 2155. // col < 2155 is wrong. It should be col <= 2155. - preValue, err1 := value.ToInt64(r.ctx.GetSessionVars().StmtCtx) + preValue, err1 := value.ToInt64(r.sctx.GetSessionVars().StmtCtx) if err1 != nil { return err1 } - *value, err = value.ConvertToMysqlYear(r.ctx.GetSessionVars().StmtCtx, col.RetType) + *value, err = value.ConvertToMysqlYear(r.sctx.GetSessionVars().StmtCtx, col.RetType) if errors.ErrorEqual(err, types.ErrWarnDataOutOfRange) { // Keep err for EQ and NE. switch *op { @@ -342,7 +349,7 @@ func (r *builder) buildFromBinOp(expr *expression.ScalarFunction, prefixLen int) } if ft.GetType() == mysql.TypeEnum && ft.EvalType() == types.ETString { - return handleEnumFromBinOp(r.ctx.GetSessionVars().StmtCtx, ft, value, op) + return handleEnumFromBinOp(r.sctx.GetSessionVars().StmtCtx, ft, value, op) } var res []*point @@ -563,7 +570,10 @@ func (*builder) buildFromIsFalse(_ *expression.ScalarFunction, isNot int) []*poi return []*point{startPoint, endPoint} } -func (r *builder) buildFromIn(expr *expression.ScalarFunction, prefixLen int) ([]*point, bool) { +func (r *builder) buildFromIn( + expr *expression.ScalarFunction, + prefixLen int, +) ([]*point, bool) { list := expr.GetArgs()[1:] rangePoints := make([]*point, 0, len(list)*2) hasNull := false @@ -596,7 +606,7 @@ func (r *builder) buildFromIn(expr *expression.ScalarFunction, prefixLen int) ([ err = parseErr } default: - dt, err = dt.ConvertTo(r.ctx.GetSessionVars().StmtCtx, expr.GetArgs()[0].GetType()) + dt, err = dt.ConvertTo(r.sctx.GetSessionVars().StmtCtx, expr.GetArgs()[0].GetType()) } if err != nil { @@ -605,7 +615,7 @@ func (r *builder) buildFromIn(expr *expression.ScalarFunction, prefixLen int) ([ } } if expr.GetArgs()[0].GetType().GetType() == mysql.TypeYear { - dt, err = dt.ConvertToMysqlYear(r.ctx.GetSessionVars().StmtCtx, expr.GetArgs()[0].GetType()) + dt, err = dt.ConvertToMysqlYear(r.sctx.GetSessionVars().StmtCtx, expr.GetArgs()[0].GetType()) if err != nil { // in (..., an impossible value (not valid year), ...), the range is empty, so skip it. continue @@ -621,7 +631,7 @@ func (r *builder) buildFromIn(expr *expression.ScalarFunction, prefixLen int) ([ endPoint := &point{value: endValue} rangePoints = append(rangePoints, startPoint, endPoint) } - sorter := pointSorter{points: rangePoints, sc: r.ctx.GetSessionVars().StmtCtx, collator: collate.GetCollator(colCollate)} + sorter := pointSorter{points: rangePoints, sc: r.sctx.GetSessionVars().StmtCtx, collator: collate.GetCollator(colCollate)} sort.Sort(&sorter) if sorter.err != nil { r.err = sorter.err @@ -645,7 +655,10 @@ func (r *builder) buildFromIn(expr *expression.ScalarFunction, prefixLen int) ([ return rangePoints, hasNull } -func (r *builder) newBuildFromPatternLike(expr *expression.ScalarFunction, prefixLen int) []*point { +func (r *builder) newBuildFromPatternLike( + expr *expression.ScalarFunction, + prefixLen int, +) []*point { _, collation := expr.CharsetAndCollation() if !collate.CompatibleCollate(expr.GetArgs()[0].GetType().GetCollate(), collation) { return getFullRange() @@ -748,7 +761,10 @@ func isPadSpaceCollation(collation string) bool { return collation != charset.CollationBin } -func (r *builder) buildFromNot(expr *expression.ScalarFunction, prefixLen int) []*point { +func (r *builder) buildFromNot( + expr *expression.ScalarFunction, + prefixLen int, +) []*point { switch n := expr.FuncName.L; n { case ast.IsTruthWithoutNull: return r.buildFromIsTrue(expr, 1, false) @@ -804,7 +820,11 @@ func (r *builder) buildFromNot(expr *expression.ScalarFunction, prefixLen int) [ return getFullRange() } -func (r *builder) buildFromScalarFunc(expr *expression.ScalarFunction, collator collate.Collator, prefixLen int) []*point { +func (r *builder) buildFromScalarFunc( + expr *expression.ScalarFunction, + collator collate.Collator, + prefixLen int, +) []*point { switch op := expr.FuncName.L; op { case ast.GE, ast.GT, ast.LT, ast.LE, ast.EQ, ast.NE, ast.NullEQ: return r.buildFromBinOp(expr, prefixLen) @@ -846,7 +866,7 @@ func (r *builder) mergeSorted(a, b []*point, collator collate.Collator) []*point ret := make([]*point, 0, len(a)+len(b)) i, j := 0, 0 for i < len(a) && j < len(b) { - less, err := rangePointLess(r.ctx.GetSessionVars().StmtCtx, a[i], b[j], collator) + less, err := rangePointLess(r.sctx.GetSessionVars().StmtCtx, a[i], b[j], collator) if err != nil { r.err = err return nil diff --git a/util/ranger/ranger.go b/util/ranger/ranger.go index b5455c185ac09..b29972988def1 100644 --- a/util/ranger/ranger.go +++ b/util/ranger/ranger.go @@ -58,13 +58,13 @@ func validInterval(sctx sessionctx.Context, low, high *point) (bool, error) { // convertPoints does some preprocessing on rangePoints to make them ready to build ranges. Preprocessing includes converting // points to the specified type, validating intervals and skipping impossible intervals. -func convertPoints(sctx sessionctx.Context, rangePoints []*point, tp *types.FieldType, skipNull bool, tableRange bool) ([]*point, error) { +func convertPoints(sctx sessionctx.Context, rangePoints []*point, newTp *types.FieldType, skipNull bool, tableRange bool) ([]*point, error) { i := 0 numPoints := len(rangePoints) var minValueDatum, maxValueDatum types.Datum if tableRange { // Currently, table's kv range cannot accept encoded value of MaxValueDatum. we need to convert it. - isUnsigned := mysql.HasUnsignedFlag(tp.GetFlag()) + isUnsigned := mysql.HasUnsignedFlag(newTp.GetFlag()) if isUnsigned { minValueDatum.SetUint64(0) maxValueDatum.SetUint64(math.MaxUint64) @@ -74,7 +74,7 @@ func convertPoints(sctx sessionctx.Context, rangePoints []*point, tp *types.Fiel } } for j := 0; j < numPoints; j += 2 { - startPoint, err := convertPoint(sctx, rangePoints[j], tp) + startPoint, err := convertPoint(sctx, rangePoints[j], newTp) if err != nil { return nil, errors.Trace(err) } @@ -86,7 +86,7 @@ func convertPoints(sctx sessionctx.Context, rangePoints []*point, tp *types.Fiel startPoint.value = minValueDatum } } - endPoint, err := convertPoint(sctx, rangePoints[j+1], tp) + endPoint, err := convertPoint(sctx, rangePoints[j+1], newTp) if err != nil { return nil, errors.Trace(err) } @@ -122,15 +122,15 @@ func estimateMemUsageForPoints2Ranges(rangePoints []*point) int64 { // Only one column is built there. If there're multiple columns, use appendPoints2Ranges. // rangeMaxSize is the max memory limit for ranges. O indicates no memory limit. // If the second return value is true, it means that the estimated memory usage of ranges exceeds rangeMaxSize and it falls back to full range. -func points2Ranges(sctx sessionctx.Context, rangePoints []*point, tp *types.FieldType, rangeMaxSize int64) (Ranges, bool, error) { - convertedPoints, err := convertPoints(sctx, rangePoints, tp, mysql.HasNotNullFlag(tp.GetFlag()), false) +func points2Ranges(sctx sessionctx.Context, rangePoints []*point, newTp *types.FieldType, rangeMaxSize int64) (Ranges, bool, error) { + convertedPoints, err := convertPoints(sctx, rangePoints, newTp, mysql.HasNotNullFlag(newTp.GetFlag()), false) if err != nil { return nil, false, errors.Trace(err) } // Estimate whether rangeMaxSize will be exceeded first before converting points to ranges. if rangeMaxSize > 0 && estimateMemUsageForPoints2Ranges(convertedPoints) > rangeMaxSize { var fullRange Ranges - if mysql.HasNotNullFlag(tp.GetFlag()) { + if mysql.HasNotNullFlag(newTp.GetFlag()) { fullRange = FullNotNullRange() } else { fullRange = FullRange() @@ -145,46 +145,46 @@ func points2Ranges(sctx sessionctx.Context, rangePoints []*point, tp *types.Fiel LowExclude: startPoint.excl, HighVal: []types.Datum{endPoint.value}, HighExclude: endPoint.excl, - Collators: []collate.Collator{collate.GetCollator(tp.GetCollate())}, + Collators: []collate.Collator{collate.GetCollator(newTp.GetCollate())}, } ranges = append(ranges, ran) } return ranges, false, nil } -func convertPoint(sctx sessionctx.Context, point *point, tp *types.FieldType) (*point, error) { +func convertPoint(sctx sessionctx.Context, point *point, newTp *types.FieldType) (*point, error) { sc := sctx.GetSessionVars().StmtCtx switch point.value.Kind() { case types.KindMaxValue, types.KindMinNotNull: return point, nil } - casted, err := point.value.ConvertTo(sc, tp) + casted, err := point.value.ConvertTo(sc, newTp) if err != nil { if sctx.GetSessionVars().StmtCtx.InPreparedPlanBuilding { // skip plan cache in this case for safety. sctx.GetSessionVars().StmtCtx.SetSkipPlanCache(errors.Errorf("%s when converting %v", err.Error(), point.value)) } //revive:disable:empty-block - if tp.GetType() == mysql.TypeYear && terror.ErrorEqual(err, types.ErrWarnDataOutOfRange) { + if newTp.GetType() == mysql.TypeYear && terror.ErrorEqual(err, types.ErrWarnDataOutOfRange) { // see issue #20101: overflow when converting integer to year - } else if tp.GetType() == mysql.TypeBit && terror.ErrorEqual(err, types.ErrDataTooLong) { + } else if newTp.GetType() == mysql.TypeBit && terror.ErrorEqual(err, types.ErrDataTooLong) { // see issue #19067: we should ignore the types.ErrDataTooLong when we convert value to TypeBit value - } else if tp.GetType() == mysql.TypeNewDecimal && terror.ErrorEqual(err, types.ErrOverflow) { + } else if newTp.GetType() == mysql.TypeNewDecimal && terror.ErrorEqual(err, types.ErrOverflow) { // Ignore the types.ErrOverflow when we convert TypeNewDecimal values. // A trimmed valid boundary point value would be returned then. Accordingly, the `excl` of the point // would be adjusted. Impossible ranges would be skipped by the `validInterval` call later. - } else if point.value.Kind() == types.KindMysqlTime && tp.GetType() == mysql.TypeTimestamp && terror.ErrorEqual(err, types.ErrWrongValue) { + } else if point.value.Kind() == types.KindMysqlTime && newTp.GetType() == mysql.TypeTimestamp && terror.ErrorEqual(err, types.ErrWrongValue) { // See issue #28424: query failed after add index // Ignore conversion from Date[Time] to Timestamp since it must be either out of range or impossible date, which will not match a point select - } else if tp.GetType() == mysql.TypeEnum && terror.ErrorEqual(err, types.ErrTruncated) { + } else if newTp.GetType() == mysql.TypeEnum && terror.ErrorEqual(err, types.ErrTruncated) { // Ignore the types.ErrorTruncated when we convert TypeEnum values. // We should cover Enum upper overflow, and convert to the biggest value. if point.value.GetInt64() > 0 { - upperEnum, err := types.ParseEnumValue(tp.GetElems(), uint64(len(tp.GetElems()))) + upperEnum, err := types.ParseEnumValue(newTp.GetElems(), uint64(len(newTp.GetElems()))) if err != nil { return nil, err } - casted.SetMysqlEnum(upperEnum, tp.GetCollate()) + casted.SetMysqlEnum(upperEnum, newTp.GetCollate()) } } else if terror.ErrorEqual(err, charset.ErrInvalidCharacterString) { // The invalid string can be produced by changing datum's underlying bytes directly. @@ -196,7 +196,7 @@ func convertPoint(sctx sessionctx.Context, point *point, tp *types.FieldType) (* } //revive:enable:empty-block } - valCmpCasted, err := point.value.Compare(sc, &casted, collate.GetCollator(tp.GetCollate())) + valCmpCasted, err := point.value.Compare(sc, &casted, collate.GetCollator(newTp.GetCollate())) if err != nil { return point, errors.Trace(err) } @@ -270,8 +270,8 @@ func estimateMemUsageForAppendPoints2Ranges(origin Ranges, rangePoints []*point) // If the second return value is true, it means that the estimated memory usage of ranges after appending points exceeds // rangeMaxSize and the function rejects appending points to ranges. func appendPoints2Ranges(sctx sessionctx.Context, origin Ranges, rangePoints []*point, - ft *types.FieldType, rangeMaxSize int64) (Ranges, bool, error) { - convertedPoints, err := convertPoints(sctx, rangePoints, ft, false, false) + newTp *types.FieldType, rangeMaxSize int64) (Ranges, bool, error) { + convertedPoints, err := convertPoints(sctx, rangePoints, newTp, false, false) if err != nil { return nil, false, errors.Trace(err) } @@ -285,7 +285,7 @@ func appendPoints2Ranges(sctx sessionctx.Context, origin Ranges, rangePoints []* if !oRange.IsPoint(sctx) { newIndexRanges = append(newIndexRanges, oRange) } else { - newRanges, err := appendPoints2IndexRange(oRange, convertedPoints, ft) + newRanges, err := appendPoints2IndexRange(oRange, convertedPoints, newTp) if err != nil { return nil, false, errors.Trace(err) } @@ -382,13 +382,13 @@ func AppendRanges2PointRanges(pointRanges Ranges, ranges Ranges, rangeMaxSize in // It will remove the nil and convert MinNotNull and MaxValue to MinInt64 or MinUint64 and MaxInt64 or MaxUint64. // rangeMaxSize is the max memory limit for ranges. O indicates no memory limit. // If the second return value is true, it means that the estimated memory usage of ranges exceeds rangeMaxSize and it falls back to full range. -func points2TableRanges(sctx sessionctx.Context, rangePoints []*point, tp *types.FieldType, rangeMaxSize int64) (Ranges, bool, error) { - convertedPoints, err := convertPoints(sctx, rangePoints, tp, true, true) +func points2TableRanges(sctx sessionctx.Context, rangePoints []*point, newTp *types.FieldType, rangeMaxSize int64) (Ranges, bool, error) { + convertedPoints, err := convertPoints(sctx, rangePoints, newTp, true, true) if err != nil { return nil, false, errors.Trace(err) } if rangeMaxSize > 0 && estimateMemUsageForPoints2Ranges(convertedPoints) > rangeMaxSize { - return FullIntRange(mysql.HasUnsignedFlag(tp.GetFlag())), true, nil + return FullIntRange(mysql.HasUnsignedFlag(newTp.GetFlag())), true, nil } ranges := make(Ranges, 0, len(convertedPoints)/2) for i := 0; i < len(convertedPoints); i += 2 { @@ -398,7 +398,7 @@ func points2TableRanges(sctx sessionctx.Context, rangePoints []*point, tp *types LowExclude: startPoint.excl, HighVal: []types.Datum{endPoint.value}, HighExclude: endPoint.excl, - Collators: []collate.Collator{collate.GetCollator(tp.GetCollate())}, + Collators: []collate.Collator{collate.GetCollator(newTp.GetCollate())}, } ranges = append(ranges, ran) } @@ -410,7 +410,7 @@ func points2TableRanges(sctx sessionctx.Context, rangePoints []*point, tp *types // The second return value is the conditions used to build ranges and the third return value is the remained conditions. func buildColumnRange(accessConditions []expression.Expression, sctx sessionctx.Context, tp *types.FieldType, tableRange bool, colLen int, rangeMaxSize int64) (Ranges, []expression.Expression, []expression.Expression, error) { - rb := builder{ctx: sctx} + rb := builder{sctx: sctx} rangePoints := getFullRange() for _, cond := range accessConditions { collator := collate.GetCollator(tp.GetCollate()) @@ -473,7 +473,7 @@ func BuildColumnRange(conds []expression.Expression, sctx sessionctx.Context, tp func (d *rangeDetacher) buildRangeOnColsByCNFCond(newTp []*types.FieldType, eqAndInCount int, accessConds []expression.Expression) (Ranges, []expression.Expression, []expression.Expression, error) { - rb := builder{ctx: d.sctx} + rb := builder{sctx: d.sctx} var ( ranges Ranges rangeFallback bool @@ -669,8 +669,10 @@ func ReachPrefixLen(v *types.Datum, length int, tp *types.FieldType) bool { return false } -// We cannot use the FieldType of column directly. e.g. the column a is int32 and we have a > 1111111111111111111. +// In util/ranger, for each datum that is used in the Range, we will convert data type for them. +// But we cannot use the FieldType of column directly. e.g. the column a is int32 and we have a > 1111111111111111111. // Obviously the constant is bigger than MaxInt32, so we will get overflow error if we use the FieldType of column a. +// In util/ranger here, we usually use "newTp" to emphasize its difference from the original FieldType of the column. func newFieldType(tp *types.FieldType) *types.FieldType { switch tp.GetType() { // To avoid overflow error. diff --git a/util/ranger/ranger_test.go b/util/ranger/ranger_test.go index 2ca841c998cb9..bac720096c8a1 100644 --- a/util/ranger/ranger_test.go +++ b/util/ranger/ranger_test.go @@ -1613,7 +1613,7 @@ create table t( exprStr: `e = "你好啊"`, accessConds: "[eq(test.t.e, 你好啊)]", filterConds: "[eq(test.t.e, 你好啊)]", - resultStr: "[[0xE4BD,0xE4BD]]", + resultStr: "[[\"\\xe4\\xbd\",\"\\xe4\\xbd\"]]", }, { indexPos: 2, @@ -1676,7 +1676,7 @@ create table t( exprStr: "d in ('aab', 'aac') and e = 'a'", accessConds: "[in(test.t.d, aab, aac) eq(test.t.e, a)]", filterConds: "[in(test.t.d, aab, aac)]", - resultStr: "[[\"aa\" 0x61,\"aa\" 0x61]]", + resultStr: "[[\"aa\" \"a\",\"aa\" \"a\"]]", }, { indexPos: 6, diff --git a/util/ranger/types.go b/util/ranger/types.go index 0024a8b039c18..c666175090763 100644 --- a/util/ranger/types.go +++ b/util/ranger/types.go @@ -269,7 +269,7 @@ func formatDatum(d types.Datum, isLeftSide bool) string { return "+inf" } case types.KindBytes: - return fmt.Sprintf("0x%X", d.GetValue()) + return fmt.Sprintf("%q", d.GetValue()) case types.KindString: return fmt.Sprintf("%q", d.GetValue()) case types.KindMysqlEnum, types.KindMysqlSet,