diff --git a/pkg/planner/core/integration_test.go b/pkg/planner/core/integration_test.go index 8c19e618f51db..fbc4151911d52 100644 --- a/pkg/planner/core/integration_test.go +++ b/pkg/planner/core/integration_test.go @@ -1873,14 +1873,14 @@ func TestPlanCacheForIndexJoinRangeFallback(t *testing.T) { tk.MustExec("drop table if exists t1, t2") tk.MustExec("create table t1(a int, b varchar(10), c varchar(10), index idx_a_b(a, b))") tk.MustExec("create table t2(d int)") - tk.MustExec("set @@tidb_opt_range_max_size=1275") - // 1275 is enough for [? a,? a], [? b,? b], [? c,? c] but is not enough for [? aaaaaa,? aaaaaa], [? bbbbbb,? bbbbbb], [? cccccc,? cccccc]. + tk.MustExec("set @@tidb_opt_range_max_size=1260") + // 1260 is enough for [? a,? a], [? b,? b], [? c,? c] but is not enough for [? aaaaaa,? aaaaaa], [? bbbbbb,? bbbbbb], [? cccccc,? cccccc]. rows := tk.MustQuery("explain format='brief' select /*+ inl_join(t1) */ * from t1 join t2 on t1.a = t2.d where t1.b in ('a', 'b', 'c')").Rows() require.True(t, strings.Contains(rows[6][4].(string), "range: decided by [eq(test.t1.a, test.t2.d) in(test.t1.b, a, b, c)]")) tk.MustQuery("show warnings").Check(testkit.Rows()) rows = tk.MustQuery("explain format='brief' select /*+ inl_join(t1) */ * from t1 join t2 on t1.a = t2.d where t1.b in ('aaaaaa', 'bbbbbb', 'cccccc');").Rows() - require.True(t, strings.Contains(rows[6][4].(string), "range: decided by [eq(test.t1.a, test.t2.d)]")) - tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 Memory capacity of 1275 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen")) + require.Contains(t, rows[6][4].(string), "range: decided by [eq(test.t1.a, test.t2.d)]") + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 Memory capacity of 1260 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen")) tk.MustExec("prepare stmt1 from 'select /*+ inl_join(t1) */ * from t1 join t2 on t1.a = t2.d where t1.b in (?, ?, ?)'") tk.MustExec("set @a='a', @b='b', @c='c'") @@ -1895,13 +1895,13 @@ func TestPlanCacheForIndexJoinRangeFallback(t *testing.T) { tk.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps}) rows = tk.MustQuery(fmt.Sprintf("explain for connection %d", tkProcess.ID)).Rows() // We don't limit range mem usage when rebuilding index join ranges for the cached plan. So [? aaaaaa,? aaaaaa], [? bbbbbb,? bbbbbb], [? cccccc,? cccccc] can be built. - require.True(t, strings.Contains(rows[6][4].(string), "range: decided by [eq(test.t1.a, test.t2.d) in(test.t1.b, aaaaaa, bbbbbb, cccccc)]")) + require.Contains(t, rows[6][4].(string), "range: decided by [eq(test.t1.a, test.t2.d) in(test.t1.b, aaaaaa, bbbbbb, cccccc)]") // Test the plan with range fallback would not be put into cache. tk.MustExec("prepare stmt2 from 'select /*+ inl_join(t1) */ * from t1 join t2 on t1.a = t2.d where t1.b in (?, ?, ?, ?, ?)'") tk.MustExec("set @a='a', @b='b', @c='c', @d='d', @e='e'") tk.MustExec("execute stmt2 using @a, @b, @c, @d, @e") - tk.MustQuery("show warnings").Sort().Check(testkit.Rows("Warning 1105 Memory capacity of 1275 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen", + tk.MustQuery("show warnings").Sort().Check(testkit.Rows("Warning 1105 Memory capacity of 1260 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen", "Warning 1105 skip prepared plan-cache: in-list is too long")) tk.MustExec("execute stmt2 using @a, @b, @c, @d, @e") tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0")) diff --git a/pkg/planner/core/testdata/index_merge_suite_out.json b/pkg/planner/core/testdata/index_merge_suite_out.json index 182dcd0ec61dd..cfa13020f7c1a 100644 --- a/pkg/planner/core/testdata/index_merge_suite_out.json +++ b/pkg/planner/core/testdata/index_merge_suite_out.json @@ -131,8 +131,8 @@ "IndexMerge 0.00 root type: intersection", "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t5, index:is1(s1) range:[\"Abc\",\"Abc\"], keep order:false, stats:pseudo", "├─IndexRangeScan(Build) 3333.33 cop[tikv] table:t5, index:is2(s2) range:(\"zzz\",+inf], keep order:false, stats:pseudo", - "├─IndexRangeScan(Build) 3323.33 cop[tikv] table:t5, index:is3(s3) range:[-inf,\"B啊a\"), keep order:false, stats:pseudo", - "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t5, index:is4(s4) range:[\"CcC\",\"CcC\"], keep order:false, stats:pseudo", + "├─IndexRangeScan(Build) 3323.33 cop[tikv] table:t5, index:is3(s3) range:[-inf,\"\\x0eJ\\xfb@\\xd5J\\x0e3\"), keep order:false, stats:pseudo", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t5, index:is4(s4) range:[\"CCC\",\"CCC\"], keep order:false, stats:pseudo", "└─TableRowIDScan(Probe) 0.00 cop[tikv] table:t5 keep order:false, stats:pseudo" ], "Result": [ @@ -144,7 +144,7 @@ "Plan": [ "IndexMerge 0.03 root type: intersection", "├─IndexRangeScan(Build) 33.33 cop[tikv] table:t6, index:PRIMARY(s1, s2) range:(\"Abc\" \"zzz\",\"Abc\" +inf], keep order:false, stats:pseudo", - "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t6, index:is3(s3) range:[\"A啊a\",\"A啊a\"], keep order:false, stats:pseudo", + "├─IndexRangeScan(Build) 10.00 cop[tikv] table:t6, index:is3(s3) range:[\"\\x0e3\\xfb@\\xd5J\\x0e3\",\"\\x0e3\\xfb@\\xd5J\\x0e3\"], keep order:false, stats:pseudo", "└─Selection(Probe) 0.03 cop[tikv] gt(test.t6.s2, \"zzz\"), not(like(test.t6.s4, \"Cd_\", 92))", " └─TableRowIDScan 0.03 cop[tikv] table:t6 keep order:false, stats:pseudo" ], @@ -172,13 +172,14 @@ { "SQL": "select /*+ use_index_merge(t8, primary,is2,is3,is4,is5) */ * from t8 where s1 like '啊A%' and s2 > 'abc' and s3 > 'cba' and s4 in ('aA', '??') and s5 = 'test,2'", "Plan": [ - "Selection 1.42 root eq(test.t8.s5, \"test,2\")", - "└─IndexMerge 0.59 root type: intersection", + "Selection 0.04 root eq(test.t8.s5, \"test,2\")", + "└─IndexMerge 0.06 root type: intersection", + " ├─IndexRangeScan(Build) 250.00 cop[tikv] table:t8, index:PRIMARY(s1) range:[\"UJ\\x00A\",\"UJ\\x00B\"), keep order:false, stats:pseudo", " ├─IndexRangeScan(Build) 3333.33 cop[tikv] table:t8, index:is2(s2) range:(\"abc\",+inf], keep order:false, stats:pseudo", " ├─IndexRangeScan(Build) 3333.33 cop[tikv] table:t8, index:is3(s3) range:(\"cba\",+inf], keep order:false, stats:pseudo", " ├─IndexRangeScan(Build) 20.00 cop[tikv] table:t8, index:is4(s4) range:[\"aA\",\"aA\"], [\"??\",\"??\"], keep order:false, stats:pseudo", - " └─Selection(Probe) 0.59 cop[tikv] gt(test.t8.s3, \"cba\"), like(test.t8.s1, \"啊A%\", 92)", - " └─TableRowIDScan 2.22 cop[tikv] table:t8 keep order:false, stats:pseudo" + " └─Selection(Probe) 0.06 cop[tikv] gt(test.t8.s3, \"cba\"), like(test.t8.s1, \"啊A%\", 92)", + " └─TableRowIDScan 0.06 cop[tikv] table:t8 keep order:false, stats:pseudo" ], "Result": [ "啊aabbccdd abcc cccc aA tEsT,2" diff --git a/pkg/util/ranger/BUILD.bazel b/pkg/util/ranger/BUILD.bazel index 935274ab75cf0..fa230a789bbf5 100644 --- a/pkg/util/ranger/BUILD.bazel +++ b/pkg/util/ranger/BUILD.bazel @@ -30,6 +30,7 @@ go_library( "//pkg/util/codec", "//pkg/util/collate", "//pkg/util/dbterror", + "//pkg/util/hack", "@com_github_pingcap_errors//:errors", ], ) diff --git a/pkg/util/ranger/checker.go b/pkg/util/ranger/checker.go index d343d27aea397..7fe2131ed162f 100644 --- a/pkg/util/ranger/checker.go +++ b/pkg/util/ranger/checker.go @@ -141,16 +141,6 @@ func (c *conditionChecker) checkScalarFunction(scalar *expression.ScalarFunction func (c *conditionChecker) checkLikeFunc(scalar *expression.ScalarFunction) (isAccessCond, shouldReserve bool) { _, collation := scalar.CharsetAndCollation() - if collate.NewCollationEnabled() && !collate.IsBinCollation(collation) { - // The algorithm constructs the range in byte-level: for example, ab% is mapped to [ab, ac] by adding 1 to the last byte. - // However, this is incorrect for non-binary collation strings because the sort key order is not the same as byte order. - // For example, "`%" is mapped to the range [`, a](where ` is 0x60 and a is 0x61). - // Because the collation utf8_general_ci is case-insensitive, a and A have the same sort key. - // Finally, the range comes to be [`, A], which is actually an empty range. - // See https://github.com/pingcap/tidb/issues/31174 for more details. - // In short, when the column type is non-binary collation string, we cannot use `like` expressions to generate the range. - return false, true - } if !collate.CompatibleCollate(scalar.GetArgs()[0].GetType().GetCollate(), collation) { return false, true } diff --git a/pkg/util/ranger/detacher.go b/pkg/util/ranger/detacher.go index 2aedcb0cea7ab..37ff8ab1ddc85 100644 --- a/pkg/util/ranger/detacher.go +++ b/pkg/util/ranger/detacher.go @@ -241,7 +241,7 @@ func compareCNFItemRangeResult(curResult, bestResult *cnfItemRangeResult) (curIs // e.g, for input CNF expressions ((a,b) in ((1,1),(2,2))) and a > 1 and ((a,b,c) in (1,1,1),(2,2,2)) // ((a,b,c) in (1,1,1),(2,2,2)) would be extracted. func extractBestCNFItemRanges(sctx sessionctx.Context, conds []expression.Expression, cols []*expression.Column, - lengths []int, rangeMaxSize int64) (*cnfItemRangeResult, []*valueInfo, error) { + lengths []int, rangeMaxSize int64, convertToSortKey bool) (*cnfItemRangeResult, []*valueInfo, error) { if len(conds) < 2 { return nil, nil, nil } @@ -260,7 +260,7 @@ func extractBestCNFItemRanges(sctx sessionctx.Context, conds []expression.Expres // We build ranges for `(a,b) in ((1,1),(1,2))` and get `[1 1, 1 1] [1 2, 1 2]`, which are point ranges and we can // append `c = 1` to the point ranges. However, if we choose to merge consecutive ranges here, we get `[1 1, 1 2]`, // which are not point ranges, and we cannot append `c = 1` anymore. - res, err := detachCondAndBuildRangeWithoutMerging(sctx, tmpConds, cols, lengths, rangeMaxSize) + res, err := detachCondAndBuildRangeWithoutMerging(sctx, tmpConds, cols, lengths, rangeMaxSize, convertToSortKey) if err != nil { return nil, nil, err } @@ -376,7 +376,7 @@ func (d *rangeDetacher) detachCNFCondAndBuildRangeForIndex(conditions []expressi ctx: d.sctx, } if considerDNF { - bestCNFItemRes, columnValues, err := extractBestCNFItemRanges(d.sctx, conditions, d.cols, d.lengths, d.rangeMaxSize) + bestCNFItemRes, columnValues, err := extractBestCNFItemRanges(d.sctx, conditions, d.cols, d.lengths, d.rangeMaxSize, d.convertToSortKey) if err != nil { return nil, err } @@ -627,12 +627,16 @@ func ExtractEqAndInCondition(sctx sessionctx.Context, conditions []expression.Ex } // Multiple Eq/In conditions for one column in CNF, apply intersection on them // Lazily compute the points for the previously visited Eq/In + newTp := newFieldType(cols[offset].GetType()) collator := collate.GetCollator(cols[offset].GetType().GetCollate()) if mergedAccesses[offset] == nil { mergedAccesses[offset] = accesses[offset] - points[offset] = rb.build(accesses[offset], collator, lengths[offset]) + // Note that this is a relatively special usage of build(). We will restore the points back to Expression for + // later use and may build the Expression to points again. + // We need to keep the original value here, which means we neither cut prefix nor convert to sort key. + points[offset] = rb.build(accesses[offset], newTp, types.UnspecifiedLength, false) } - points[offset] = rb.intersection(points[offset], rb.build(cond, collator, lengths[offset]), collator) + points[offset] = rb.intersection(points[offset], rb.build(cond, newTp, types.UnspecifiedLength, false), collator) if len(points[offset]) == 0 { // Early termination if false expression found if expression.MaybeOverOptimized4PlanCache(sctx, conditions) { // `a>@x and a<@y` --> `invalid-range if @x>=@y` @@ -773,9 +777,10 @@ func (d *rangeDetacher) detachDNFCondAndBuildRangeForIndex(condition *expression if shouldReserve { hasResidual = true } - points := rb.build(item, collate.GetCollator(newTpSlice[0].GetCollate()), d.lengths[0]) + points := rb.build(item, newTpSlice[0], d.lengths[0], d.convertToSortKey) + tmpNewTp := convertStringFTToBinaryCollate(newTpSlice[0]) // TODO: restrict the mem usage of ranges - ranges, rangeFallback, err := points2Ranges(d.sctx, points, newTpSlice[0], d.rangeMaxSize) + ranges, rangeFallback, err := points2Ranges(d.sctx, points, tmpNewTp, d.rangeMaxSize) if err != nil { return nil, nil, nil, false, errors.Trace(err) } @@ -867,6 +872,7 @@ func DetachCondAndBuildRangeForIndex(sctx sessionctx.Context, conditions []expre cols: cols, lengths: lengths, mergeConsecutive: true, + convertToSortKey: true, rangeMaxSize: rangeMaxSize, } return d.detachCondAndBuildRangeForCols() @@ -875,13 +881,14 @@ func DetachCondAndBuildRangeForIndex(sctx sessionctx.Context, conditions []expre // detachCondAndBuildRangeWithoutMerging detaches the index filters from table filters and uses them to build ranges. // When building ranges, it doesn't merge consecutive ranges. func detachCondAndBuildRangeWithoutMerging(sctx sessionctx.Context, conditions []expression.Expression, cols []*expression.Column, - lengths []int, rangeMaxSize int64) (*DetachRangeResult, error) { + lengths []int, rangeMaxSize int64, convertToSortKey bool) (*DetachRangeResult, error) { d := &rangeDetacher{ sctx: sctx, allConds: conditions, cols: cols, lengths: lengths, mergeConsecutive: false, + convertToSortKey: convertToSortKey, rangeMaxSize: rangeMaxSize, } return d.detachCondAndBuildRangeForCols() @@ -893,7 +900,7 @@ func detachCondAndBuildRangeWithoutMerging(sctx sessionctx.Context, conditions [ // The returned values are encapsulated into a struct DetachRangeResult, see its comments for explanation. func DetachCondAndBuildRangeForPartition(sctx sessionctx.Context, conditions []expression.Expression, cols []*expression.Column, lengths []int, rangeMaxSize int64) (*DetachRangeResult, error) { - return detachCondAndBuildRangeWithoutMerging(sctx, conditions, cols, lengths, rangeMaxSize) + return detachCondAndBuildRangeWithoutMerging(sctx, conditions, cols, lengths, rangeMaxSize, false) } type rangeDetacher struct { @@ -902,6 +909,7 @@ type rangeDetacher struct { cols []*expression.Column lengths []int mergeConsecutive bool + convertToSortKey bool rangeMaxSize int64 } @@ -948,6 +956,7 @@ func DetachSimpleCondAndBuildRangeForIndex(sctx sessionctx.Context, conditions [ cols: cols, lengths: lengths, mergeConsecutive: true, + convertToSortKey: true, rangeMaxSize: rangeMaxSize, } res, err := d.detachCNFCondAndBuildRangeForIndex(conditions, newTpSlice, false) diff --git a/pkg/util/ranger/points.go b/pkg/util/ranger/points.go index c93ac64dbf192..872aa72f79b2e 100644 --- a/pkg/util/ranger/points.go +++ b/pkg/util/ranger/points.go @@ -31,6 +31,7 @@ import ( "github.com/pingcap/tidb/pkg/util/chunk" "github.com/pingcap/tidb/pkg/util/collate" "github.com/pingcap/tidb/pkg/util/dbterror" + "github.com/pingcap/tidb/pkg/util/hack" ) // Error instances. @@ -135,6 +136,50 @@ func rangePointEqualValueLess(a, b *point) bool { return a.excl && !b.excl } +func pointsConvertToSortKey(sctx sessionctx.Context, inputPs []*point, newTp *types.FieldType) ([]*point, error) { + // Only handle normal string type here. + // Currently, set won't be pushed down and it shouldn't reach here in theory. + // For enum, we have separate logic for it, like handleEnumFromBinOp(). For now, it only supports point range, + // intervals are not supported. So we also don't need to handle enum here. + if newTp.EvalType() != types.ETString || + newTp.GetType() == mysql.TypeEnum || + newTp.GetType() == mysql.TypeSet { + return inputPs, nil + } + ps := make([]*point, 0, len(inputPs)) + for _, p := range inputPs { + np, err := pointConvertToSortKey(sctx, p, newTp, true) + if err != nil { + return nil, err + } + ps = append(ps, np) + } + return ps, nil +} + +func pointConvertToSortKey( + sctx sessionctx.Context, + inputP *point, + newTp *types.FieldType, + trimTrailingSpace bool, +) (*point, error) { + p, err := convertPoint(sctx, inputP, newTp) + if err != nil { + return nil, err + } + if p.value.Kind() != types.KindString || newTp.GetCollate() == charset.CollationBin || !collate.NewCollationEnabled() { + return p, nil + } + sortKey := p.value.GetBytes() + if !trimTrailingSpace { + sortKey = collate.GetCollator(newTp.GetCollate()).KeyWithoutTrimRightSpace(string(hack.String(sortKey))) + } else { + sortKey = collate.GetCollator(newTp.GetCollate()).Key(string(hack.String(sortKey))) + } + + return &point{value: types.NewBytesDatum(sortKey), excl: p.excl, start: p.start}, nil +} + func (r *pointSorter) Swap(i, j int) { r.points[i], r.points[j] = r.points[j], r.points[i] } @@ -188,21 +233,23 @@ type builder struct { } // build converts Expression on one column into point, which can be further built into Range. -// The input collator is used for intersection/union between points, which corresponds to AND/OR in the expression. Since -// our (*Datum).Compare(), which is used there, needs an explicit collator input to handle comparison for string and bytes, -// 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(). +// convertToSortKey indicates whether the string values should be converted to sort key. +// Converting to sort key can make `like` function be built into Range for new collation column. But we can't restore +// the original value from the sort key, so the usage of the result may be limited, like when you need to restore the +// result points back to Expression. func (r *builder) build( expr expression.Expression, - collator collate.Collator, + newTp *types.FieldType, prefixLen int, + convertToSortKey bool, ) []*point { switch x := expr.(type) { case *expression.Column: return r.buildFromColumn() case *expression.ScalarFunction: - return r.buildFromScalarFunc(x, collator, prefixLen) + return r.buildFromScalarFunc(x, newTp, prefixLen, convertToSortKey) case *expression.Constant: return r.buildFromConstant(x) } @@ -246,7 +293,9 @@ func (*builder) buildFromColumn() []*point { func (r *builder) buildFromBinOp( expr *expression.ScalarFunction, + newTp *types.FieldType, prefixLen int, + convertToSortKey bool, ) []*point { // This has been checked that the binary operation is comparison operation, and one of // the operand is column name expression. @@ -390,6 +439,13 @@ func (r *builder) buildFromBinOp( res = []*point{startPoint, endPoint} } cutPrefixForPoints(res, prefixLen, ft) + if convertToSortKey { + res, err = pointsConvertToSortKey(r.sctx, res, newTp) + if err != nil { + r.err = err + return getFullRange() + } + } return res } @@ -574,7 +630,9 @@ func (*builder) buildFromIsFalse(_ *expression.ScalarFunction, isNot int) []*poi func (r *builder) buildFromIn( expr *expression.ScalarFunction, + newTp *types.FieldType, prefixLen int, + convertToSortKey bool, ) ([]*point, bool) { list := expr.GetArgs()[1:] rangePoints := make([]*point, 0, len(list)*2) @@ -655,12 +713,22 @@ func (r *builder) buildFromIn( } rangePoints = rangePoints[:curPos] cutPrefixForPoints(rangePoints, prefixLen, ft) + var err error + if convertToSortKey { + rangePoints, err = pointsConvertToSortKey(r.sctx, rangePoints, newTp) + if err != nil { + r.err = err + return getFullRange(), false + } + } return rangePoints, hasNull } func (r *builder) newBuildFromPatternLike( expr *expression.ScalarFunction, + newTp *types.FieldType, prefixLen int, + convertToSortKey bool, ) []*point { _, collation := expr.CharsetAndCollation() if !collate.CompatibleCollate(expr.GetArgs()[0].GetType().GetCollate(), collation) { @@ -677,10 +745,18 @@ func (r *builder) newBuildFromPatternLike( r.err = errors.Trace(err) return getFullRange() } + // non-exceptional return case 1: empty pattern if pattern == "" { startPoint := &point{value: types.NewStringDatum(""), start: true} endPoint := &point{value: types.NewStringDatum("")} res := []*point{startPoint, endPoint} + if convertToSortKey { + res, err = pointsConvertToSortKey(r.sctx, res, newTp) + if err != nil { + r.err = err + return getFullRange() + } + } return res } lowValue := make([]byte, 0, len(pattern)) @@ -722,33 +798,72 @@ func (r *builder) newBuildFromPatternLike( } lowValue = append(lowValue, pattern[i]) } + // non-exceptional return case 2: no characters before the wildcard if len(lowValue) == 0 { return []*point{{value: types.MinNotNullDatum(), start: true}, {value: types.MaxValueDatum()}} } + // non-exceptional return case 3: pattern contains valid characters and doesn't contain the wildcard if isExactMatch { val := types.NewCollationStringDatum(string(lowValue), tpOfPattern.GetCollate()) startPoint := &point{value: val, start: true} endPoint := &point{value: val} res := []*point{startPoint, endPoint} cutPrefixForPoints(res, prefixLen, tpOfPattern) + if convertToSortKey { + res, err = pointsConvertToSortKey(r.sctx, res, newTp) + if err != nil { + r.err = err + return getFullRange() + } + } return res } - startPoint := &point{start: true, excl: exclude} - startPoint.value.SetBytesAsString(lowValue, tpOfPattern.GetCollate(), uint32(tpOfPattern.GetFlen())) - cutPrefixForPoints([]*point{startPoint}, prefixLen, tpOfPattern) - highValue := make([]byte, len(lowValue)) - copy(highValue, lowValue) - endPoint := &point{excl: true} - for i := len(highValue) - 1; i >= 0; i-- { + + // non-exceptional return case 4: pattern contains valid characters and contains the wildcard + + // non-exceptional return case 4-1 + // If it's not a _bin or binary collation, and we don't convert the value to the sort key, we can't build + // a range for the wildcard. + if !convertToSortKey && + !collate.IsBinCollation(tpOfPattern.GetCollate()) { + return []*point{{value: types.MinNotNullDatum(), start: true}, {value: types.MaxValueDatum()}} + } + + // non-exceptional return case 4-2: build a range for the wildcard + // the end_key is sortKey(start_value) + 1 + originalStartPoint := &point{start: true, excl: exclude} + originalStartPoint.value.SetBytesAsString(lowValue, tpOfPattern.GetCollate(), uint32(tpOfPattern.GetFlen())) + cutPrefixForPoints([]*point{originalStartPoint}, prefixLen, tpOfPattern) + + // If we don't trim the trailing spaces, which means using KeyWithoutTrimRightSpace() instead of Key(), we can build + // a smaller range for better performance, e.g., LIKE ' %'. + // However, if it's a PAD SPACE collation, we must trim the trailing spaces for the start point to ensure the correctness. + // Because the trailing spaces are trimmed in the stored index key. For example, for LIKE 'abc %' on utf8mb4_bin + // column, the start key should be 'abd' instead of 'abc ', but the end key can be 'abc!'. ( ' ' is 32 and '!' is 33 + // in ASCII) + shouldTrimTrailingSpace := isPadSpaceCollation(collation) + startPoint, err := pointConvertToSortKey(r.sctx, originalStartPoint, newTp, shouldTrimTrailingSpace) + if err != nil { + r.err = errors.Trace(err) + return getFullRange() + } + sortKeyPointWithoutTrim, err := pointConvertToSortKey(r.sctx, originalStartPoint, newTp, false) + if err != nil { + r.err = errors.Trace(err) + return getFullRange() + } + sortKeyWithoutTrim := append([]byte{}, sortKeyPointWithoutTrim.value.GetBytes()...) + endPoint := &point{value: types.MaxValueDatum(), excl: true} + for i := len(sortKeyWithoutTrim) - 1; i >= 0; i-- { // Make the end point value more than the start point value, // and the length of the end point value is the same as the length of the start point value. // e.g., the start point value is "abc", so the end point value is "abd". - highValue[i]++ - if highValue[i] != 0 { - endPoint.value.SetBytesAsString(highValue, tpOfPattern.GetCollate(), uint32(tpOfPattern.GetFlen())) + sortKeyWithoutTrim[i]++ + if sortKeyWithoutTrim[i] != 0 { + endPoint.value.SetBytes(sortKeyWithoutTrim) break } - // If highValue[i] is 255 and highValue[i]++ is 0, then the end point value is max value. + // If sortKeyWithoutTrim[i] is 255 and sortKeyWithoutTrim[i]++ is 0, then the end point value is max value. if i == 0 { endPoint.value = types.MaxValueDatum() } @@ -766,7 +881,9 @@ func isPadSpaceCollation(collation string) bool { func (r *builder) buildFromNot( expr *expression.ScalarFunction, + newTp *types.FieldType, prefixLen int, + convertToSortKey bool, ) []*point { switch n := expr.FuncName.L; n { case ast.IsTruthWithoutNull: @@ -780,7 +897,14 @@ func (r *builder) buildFromNot( isUnsignedIntCol bool nonNegativePos int ) - rangePoints, hasNull := r.buildFromIn(expr, types.UnspecifiedLength) + // Note that we must handle the cutting prefix and converting to sort key in buildFromNot, because if we cut the + // prefix inside buildFromIn(), the inversion logic here would make an incomplete and wrong range. + // For example, for index col(1), col NOT IN ('aaa', 'bbb'), if we cut the prefix in buildFromIn(), we would get + // ['a', 'a'], ['b', 'b'] from there. Then after in this function we would get ['' 'a'), ('a', 'b'), ('b', +inf] + // as the result. This is wrong because data like 'ab' would be missed. Actually we are unable to build a range + // for this case. + // So we must cut the prefix in this function, therefore converting to sort key must also be done here. + rangePoints, hasNull := r.buildFromIn(expr, newTp, types.UnspecifiedLength, false) if hasNull { return nil } @@ -807,6 +931,14 @@ func (r *builder) buildFromNot( retRangePoints = append(retRangePoints, &point{value: previousValue, start: true, excl: true}) retRangePoints = append(retRangePoints, &point{value: types.MaxValueDatum()}) cutPrefixForPoints(retRangePoints, prefixLen, expr.GetArgs()[0].GetType()) + if convertToSortKey { + var err error + retRangePoints, err = pointsConvertToSortKey(r.sctx, retRangePoints, newTp) + if err != nil { + r.err = err + return getFullRange() + } + } return retRangePoints case ast.Like: // Pattern not like is not supported. @@ -825,16 +957,25 @@ func (r *builder) buildFromNot( func (r *builder) buildFromScalarFunc( expr *expression.ScalarFunction, - collator collate.Collator, + newTp *types.FieldType, prefixLen int, + convertToSortKey bool, ) []*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) + return r.buildFromBinOp(expr, newTp, prefixLen, convertToSortKey) case ast.LogicAnd: - return r.intersection(r.build(expr.GetArgs()[0], collator, prefixLen), r.build(expr.GetArgs()[1], collator, prefixLen), collator) + collator := collate.GetCollator(newTp.GetCollate()) + if convertToSortKey { + collator = collate.GetCollator(charset.CollationBin) + } + return r.intersection(r.build(expr.GetArgs()[0], newTp, prefixLen, convertToSortKey), r.build(expr.GetArgs()[1], newTp, prefixLen, convertToSortKey), collator) case ast.LogicOr: - return r.union(r.build(expr.GetArgs()[0], collator, prefixLen), r.build(expr.GetArgs()[1], collator, prefixLen), collator) + collator := collate.GetCollator(newTp.GetCollate()) + if convertToSortKey { + collator = collate.GetCollator(charset.CollationBin) + } + return r.union(r.build(expr.GetArgs()[0], newTp, prefixLen, convertToSortKey), r.build(expr.GetArgs()[1], newTp, prefixLen, convertToSortKey), collator) case ast.IsTruthWithoutNull: return r.buildFromIsTrue(expr, 0, false) case ast.IsTruthWithNull: @@ -842,25 +983,31 @@ func (r *builder) buildFromScalarFunc( case ast.IsFalsity: return r.buildFromIsFalse(expr, 0) case ast.In: - retPoints, _ := r.buildFromIn(expr, prefixLen) + retPoints, _ := r.buildFromIn(expr, newTp, prefixLen, convertToSortKey) return retPoints case ast.Like: - return r.newBuildFromPatternLike(expr, prefixLen) + return r.newBuildFromPatternLike(expr, newTp, prefixLen, convertToSortKey) case ast.IsNull: startPoint := &point{start: true} endPoint := &point{} return []*point{startPoint, endPoint} case ast.UnaryNot: - return r.buildFromNot(expr.GetArgs()[0].(*expression.ScalarFunction), prefixLen) + return r.buildFromNot(expr.GetArgs()[0].(*expression.ScalarFunction), newTp, prefixLen, convertToSortKey) } return nil } +// We need an input collator because our (*Datum).Compare(), which is used in this method, needs an explicit collator +// input to handle comparison for string and bytes. +// Note that if the points are converted to sort key, the collator should be set to charset.CollationBin. func (r *builder) intersection(a, b []*point, collator collate.Collator) []*point { return r.merge(a, b, false, collator) } +// We need an input collator because our (*Datum).Compare(), which is used in this method, needs an explicit collator +// input to handle comparison for string and bytes. +// Note that if the points are converted to sort key, the collator should be set to charset.CollationBin. func (r *builder) union(a, b []*point, collator collate.Collator) []*point { return r.merge(a, b, true, collator) } diff --git a/pkg/util/ranger/ranger.go b/pkg/util/ranger/ranger.go index 88af565795c19..01a381c5f6b26 100644 --- a/pkg/util/ranger/ranger.go +++ b/pkg/util/ranger/ranger.go @@ -413,10 +413,11 @@ func points2TableRanges(sctx sessionctx.Context, rangePoints []*point, newTp *ty 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{sctx: sctx} + newTp := newFieldType(tp) rangePoints := getFullRange() for _, cond := range accessConditions { - collator := collate.GetCollator(tp.GetCollate()) - rangePoints = rb.intersection(rangePoints, rb.build(cond, collator, colLen), collator) + collator := collate.GetCollator(charset.CollationBin) + rangePoints = rb.intersection(rangePoints, rb.build(cond, newTp, colLen, true), collator) if rb.err != nil { return nil, nil, nil, errors.Trace(rb.err) } @@ -426,7 +427,7 @@ func buildColumnRange(accessConditions []expression.Expression, sctx sessionctx. rangeFallback bool err error ) - newTp := newFieldType(tp) + newTp = convertStringFTToBinaryCollate(newTp) if tableRange { ranges, rangeFallback, err = points2TableRanges(sctx, rangePoints, newTp, rangeMaxSize) } else { @@ -483,14 +484,15 @@ func (d *rangeDetacher) buildRangeOnColsByCNFCond(newTp []*types.FieldType, eqAn ) for i := 0; i < eqAndInCount; i++ { // Build ranges for equal or in access conditions. - point := rb.build(accessConds[i], collate.GetCollator(newTp[i].GetCollate()), d.lengths[i]) + point := rb.build(accessConds[i], newTp[i], d.lengths[i], d.convertToSortKey) if rb.err != nil { return nil, nil, nil, errors.Trace(rb.err) } + tmpNewTp := convertStringFTToBinaryCollate(newTp[i]) if i == 0 { - ranges, rangeFallback, err = points2Ranges(d.sctx, point, newTp[i], d.rangeMaxSize) + ranges, rangeFallback, err = points2Ranges(d.sctx, point, tmpNewTp, d.rangeMaxSize) } else { - ranges, rangeFallback, err = appendPoints2Ranges(d.sctx, ranges, point, newTp[i], d.rangeMaxSize) + ranges, rangeFallback, err = appendPoints2Ranges(d.sctx, ranges, point, tmpNewTp, d.rangeMaxSize) } if err != nil { return nil, nil, nil, errors.Trace(err) @@ -504,15 +506,26 @@ func (d *rangeDetacher) buildRangeOnColsByCNFCond(newTp []*types.FieldType, eqAn // Build rangePoints for non-equal access conditions. for i := eqAndInCount; i < len(accessConds); i++ { collator := collate.GetCollator(newTp[eqAndInCount].GetCollate()) - rangePoints = rb.intersection(rangePoints, rb.build(accessConds[i], collator, d.lengths[eqAndInCount]), collator) + if d.convertToSortKey { + collator = collate.GetCollator(charset.CollationBin) + } + rangePoints = rb.intersection(rangePoints, rb.build(accessConds[i], newTp[eqAndInCount], d.lengths[eqAndInCount], d.convertToSortKey), collator) if rb.err != nil { return nil, nil, nil, errors.Trace(rb.err) } } + var tmpNewTp *types.FieldType + if eqAndInCount == 0 || eqAndInCount < len(accessConds) { + if d.convertToSortKey { + tmpNewTp = convertStringFTToBinaryCollate(newTp[eqAndInCount]) + } else { + tmpNewTp = newTp[eqAndInCount] + } + } if eqAndInCount == 0 { - ranges, rangeFallback, err = points2Ranges(d.sctx, rangePoints, newTp[0], d.rangeMaxSize) + ranges, rangeFallback, err = points2Ranges(d.sctx, rangePoints, tmpNewTp, d.rangeMaxSize) } else if eqAndInCount < len(accessConds) { - ranges, rangeFallback, err = appendPoints2Ranges(d.sctx, ranges, rangePoints, newTp[eqAndInCount], d.rangeMaxSize) + ranges, rangeFallback, err = appendPoints2Ranges(d.sctx, ranges, rangePoints, tmpNewTp, d.rangeMaxSize) } if err != nil { return nil, nil, nil, errors.Trace(err) @@ -524,6 +537,18 @@ func (d *rangeDetacher) buildRangeOnColsByCNFCond(newTp []*types.FieldType, eqAn return ranges, accessConds, nil, nil } +func convertStringFTToBinaryCollate(ft *types.FieldType) *types.FieldType { + if ft.EvalType() != types.ETString || + ft.GetType() == mysql.TypeEnum || + ft.GetType() == mysql.TypeSet { + return ft + } + newTp := ft.Clone() + newTp.SetCharset(charset.CharsetBin) + newTp.SetCollate(charset.CollationBin) + return newTp +} + // buildCNFIndexRange builds the range for index where the top layer is CNF. func (d *rangeDetacher) buildCNFIndexRange(newTp []*types.FieldType, eqAndInCount int, accessConds []expression.Expression) (Ranges, []expression.Expression, []expression.Expression, error) { diff --git a/pkg/util/ranger/ranger_test.go b/pkg/util/ranger/ranger_test.go index 0c8523255a836..3e1575e92c83b 100644 --- a/pkg/util/ranger/ranger_test.go +++ b/pkg/util/ranger/ranger_test.go @@ -1338,21 +1338,21 @@ create table t( exprStr: "f >= 'a' and f <= 'B'", accessConds: "[ge(test.t.f, a) le(test.t.f, B)]", filterConds: "[]", - resultStr: "[[\"a\",\"B\"]]", + resultStr: "[[\"\\x00A\",\"\\x00B\"]]", }, { indexPos: 4, exprStr: "f in ('a', 'B')", accessConds: "[in(test.t.f, a, B)]", filterConds: "[]", - resultStr: "[[\"a\",\"a\"] [\"B\",\"B\"]]", + resultStr: "[[\"\\x00A\",\"\\x00A\"] [\"\\x00B\",\"\\x00B\"]]", }, { indexPos: 4, exprStr: "f = 'a' and f = 'B' collate utf8mb4_bin", accessConds: "[eq(test.t.f, a)]", filterConds: "[eq(test.t.f, B)]", - resultStr: "[[\"a\",\"a\"]]", + resultStr: "[[\"\\x00A\",\"\\x00A\"]]", }, { indexPos: 4, diff --git a/tests/integrationtest/r/expression/charset_and_collation.result b/tests/integrationtest/r/expression/charset_and_collation.result index c4764744183e6..4e792011683ba 100644 --- a/tests/integrationtest/r/expression/charset_and_collation.result +++ b/tests/integrationtest/r/expression/charset_and_collation.result @@ -1895,7 +1895,7 @@ c 1 explain format="brief" select v from t where v < 'b' order by v; id estRows task access object operator info IndexReader 3323.33 root index:IndexRangeScan -└─IndexRangeScan 3323.33 cop[tikv] table:t, index:v(v) range:[-inf,"b"), keep order:true, stats:pseudo +└─IndexRangeScan 3323.33 cop[tikv] table:t, index:v(v) range:[-inf,"\x00B"), keep order:true, stats:pseudo select v from t where v < 'b' order by v; v @@ -1906,7 +1906,7 @@ a explain format="brief" select v from t where v < 'b' and v > ' ' order by v; id estRows task access object operator info IndexReader 250.00 root index:IndexRangeScan -└─IndexRangeScan 250.00 cop[tikv] table:t, index:v(v) range:(" ","b"), keep order:true, stats:pseudo +└─IndexRangeScan 250.00 cop[tikv] table:t, index:v(v) range:("","\x00B"), keep order:true, stats:pseudo select v from t where v < 'b' and v > ' ' order by v; v a @@ -1932,7 +1932,7 @@ explain format="brief" select id from t use index(v) where v < 'b'; id estRows task access object operator info Projection 3323.33 root expression__charset_and_collation.t.id └─IndexLookUp 3323.33 root - ├─IndexRangeScan(Build) 3323.33 cop[tikv] table:t, index:v(v) range:[-inf,"b"), keep order:false, stats:pseudo + ├─IndexRangeScan(Build) 3323.33 cop[tikv] table:t, index:v(v) range:[-inf,"\x00B"), keep order:false, stats:pseudo └─TableRowIDScan(Probe) 3323.33 cop[tikv] table:t keep order:false, stats:pseudo select id from t use index(v) where v < 'b'; id @@ -1945,7 +1945,7 @@ explain format="brief" select id from t use index(v) where v < 'b' and v > ' '; id estRows task access object operator info Projection 250.00 root expression__charset_and_collation.t.id └─IndexLookUp 250.00 root - ├─IndexRangeScan(Build) 250.00 cop[tikv] table:t, index:v(v) range:(" ","b"), keep order:false, stats:pseudo + ├─IndexRangeScan(Build) 250.00 cop[tikv] table:t, index:v(v) range:("","\x00B"), keep order:false, stats:pseudo └─TableRowIDScan(Probe) 250.00 cop[tikv] table:t keep order:false, stats:pseudo select id from t use index(v) where v < 'b' and v > ' '; id diff --git a/tests/integrationtest/r/expression/issues.result b/tests/integrationtest/r/expression/issues.result index 0e22481096b0d..adf6d00292199 100644 --- a/tests/integrationtest/r/expression/issues.result +++ b/tests/integrationtest/r/expression/issues.result @@ -2094,9 +2094,9 @@ create table t(a char(4) collate utf8_general_ci primary key /*T![clustered_inde insert into t values('`?'); explain format='brief' select * from t where a like '`%'; id estRows task access object operator info -TableReader 8000.00 root data:Selection -└─Selection 8000.00 cop[tikv] like(expression__issues.t.a, "`%", 92) - └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +TableReader 250.00 root data:Selection +└─Selection 250.00 cop[tikv] like(expression__issues.t.a, "`%", 92) + └─TableRangeScan 250.00 cop[tikv] table:t range:["\x00`","\x00a"), keep order:false, stats:pseudo select * from t where a like '`%'; a `? diff --git a/tests/integrationtest/r/planner/core/issuetest/planner_issue.result b/tests/integrationtest/r/planner/core/issuetest/planner_issue.result index 5b5aae65d4adb..265eb9f1aba8a 100644 --- a/tests/integrationtest/r/planner/core/issuetest/planner_issue.result +++ b/tests/integrationtest/r/planner/core/issuetest/planner_issue.result @@ -267,7 +267,7 @@ Projection 250.00 root planner__core__issuetest__planner_issue.t1.a, length(pla └─UnionScan 250.00 root like(planner__core__issuetest__planner_issue.t1.a, "测试 %", 92) └─IndexReader 250.00 root index:Selection └─Selection 250.00 cop[tikv] like(planner__core__issuetest__planner_issue.t1.a, "测试 %", 92) - └─IndexRangeScan 250.00 cop[tikv] table:t1, index:ia(a) range:["测试 ","测试!"), keep order:false, stats:pseudo + └─IndexRangeScan 250.00 cop[tikv] table:t1, index:ia(a) range:["测试","测试!"), keep order:false, stats:pseudo explain format = brief select *,length(a) from t1 where a like '测试'; id estRows task access object operator info Projection 10.00 root planner__core__issuetest__planner_issue.t1.a, length(planner__core__issuetest__planner_issue.t1.a)->Column#3 @@ -295,18 +295,18 @@ create table t2(a varchar(20) collate gbk_chinese_ci, index ia(a)); insert into t2 value('测试'),('测试 '); explain format = brief select *,length(a) from t2 where a like '测试 %'; id estRows task access object operator info -Projection 8000.00 root planner__core__issuetest__planner_issue.t2.a, length(to_binary(planner__core__issuetest__planner_issue.t2.a))->Column#3 -└─UnionScan 8000.00 root like(planner__core__issuetest__planner_issue.t2.a, "测试 %", 92) - └─TableReader 8000.00 root data:Selection - └─Selection 8000.00 cop[tikv] like(planner__core__issuetest__planner_issue.t2.a, "测试 %", 92) - └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo +Projection 250.00 root planner__core__issuetest__planner_issue.t2.a, length(to_binary(planner__core__issuetest__planner_issue.t2.a))->Column#3 +└─UnionScan 250.00 root like(planner__core__issuetest__planner_issue.t2.a, "测试 %", 92) + └─IndexReader 250.00 root index:Selection + └─Selection 250.00 cop[tikv] like(planner__core__issuetest__planner_issue.t2.a, "测试 %", 92) + └─IndexRangeScan 250.00 cop[tikv] table:t2, index:ia(a) range:["\x89\a\xba%","\x89\a\xba%!"), keep order:false, stats:pseudo explain format = brief select *,length(a) from t2 where a like '测试'; id estRows task access object operator info -Projection 8000.00 root planner__core__issuetest__planner_issue.t2.a, length(to_binary(planner__core__issuetest__planner_issue.t2.a))->Column#3 -└─UnionScan 8000.00 root like(planner__core__issuetest__planner_issue.t2.a, "测试", 92) - └─TableReader 8000.00 root data:Selection - └─Selection 8000.00 cop[tikv] like(planner__core__issuetest__planner_issue.t2.a, "测试", 92) - └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo +Projection 10.00 root planner__core__issuetest__planner_issue.t2.a, length(to_binary(planner__core__issuetest__planner_issue.t2.a))->Column#3 +└─UnionScan 10.00 root like(planner__core__issuetest__planner_issue.t2.a, "测试", 92) + └─IndexReader 10.00 root index:Selection + └─Selection 10.00 cop[tikv] like(planner__core__issuetest__planner_issue.t2.a, "测试", 92) + └─IndexRangeScan 10.00 cop[tikv] table:t2, index:ia(a) range:["\x89\a\xba%","\x89\a\xba%"], keep order:false, stats:pseudo select *,length(a) from t2 where a like '测试 %'; a length(a) 测试 6 diff --git a/tests/integrationtest/r/planner/core/range_scan_for_like.result b/tests/integrationtest/r/planner/core/range_scan_for_like.result index 7dfdb7e8fb116..058de729e4589 100644 --- a/tests/integrationtest/r/planner/core/range_scan_for_like.result +++ b/tests/integrationtest/r/planner/core/range_scan_for_like.result @@ -2,11 +2,11 @@ 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["mK\x8b\xd5","mK\x8b\xd6"), 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 @@ -14,11 +14,11 @@ a length(a) 测试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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测%%", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["mK","mL"), 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 @@ -28,21 +28,21 @@ a length(a) 测试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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测%%试", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["mK","mL"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%%", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["mK\x8b\xd5","mK\x8b\xd6"), 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 @@ -50,100 +50,100 @@ a length(a) 测试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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试_", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["mK\x8b\xd5","mK\x8b\xd6"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "你好%", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["O`Y}","O`Y~"), 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 +Projection_6 10.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 10.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 10.00 root index:Selection_15 + └─Selection_15 10.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa", 92) + └─IndexRangeScan_14 10.00 cop[tikv] table:t, index:ia(a) range:["\x00A\x00A","\x00A\x00A"], 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["\x00A\x00A","\x00A\x00B"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%cc", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["\x00A\x00A","\x00A\x00B"), 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 +Projection_6 10.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 10.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 10.00 root index:Selection_15 + └─Selection_15 10.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "", 92) + └─IndexRangeScan_14 10.00 cop[tikv] table:t, index:ia(a) range:["",""], 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 +Projection_6 10.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 10.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 10.00 root index:Selection_15 + └─Selection_15 10.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " ", 92) + └─IndexRangeScan_14 10.00 cop[tikv] table:t, index:ia(a) range:["",""], 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%dd", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["\x00A\x00A","\x00A\x00B"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%%dd", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["\x00A\x00A","\x00A\x00B"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa_bccdd", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["\x00A\x00A","\x00A\x00B"), 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 @@ -171,11 +171,11 @@ aABBccdd 8 测试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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %%", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["","\x00!"), 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 @@ -184,31 +184,31 @@ 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %%语言", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["","\x00!"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 %", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["\x00 \x00 \x8b\xed","\x00 \x00 \x8b\xed\x00!"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Projection_13 250.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 250.00 root index:Selection_15 + └─Selection_15 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 _", 92) + └─IndexRangeScan_14 250.00 cop[tikv] table:t, index:ia(a) range:["\x00 \x00 \x8b\xed","\x00 \x00 \x8b\xed\x00 \x00!"), 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; @@ -216,24 +216,24 @@ 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\xfb@\xedK\xfbA\x8b\xd5","\xfb@\xedK\xfbA\x8b\xd6"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测%%", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\xfb@\xedK","\xfb@\xedL"), 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 @@ -241,120 +241,118 @@ a length(a) 测试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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测%%试", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\xfb@\xedK","\xfb@\xedL"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%%", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\xfb@\xedK\xfbA\x8b\xd5","\xfb@\xedK\xfbA\x8b\xd6"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试_", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\xfb@\xedK\xfbA\x8b\xd5","\xfb@\xedK\xfbA\x8b\xd6"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "你好%", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\xfb@\xcf`\xfb@\xd9}","\xfb@\xcf`\xfb@\xd9~"), 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 +Projection_6 1.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 1.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 1.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 + └─Selection_11 1.00 root like(planner__core__range_scan_for_like.t.a, "aa", 92) + └─Point_Get_10 1.00 root table:t, index:ia(a) 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\x0e3\x0e3","\x0e3\x0e4"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%cc", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\x0e3\x0e3","\x0e3\x0e4"), 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 +Projection_6 1.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 1.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 1.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 + └─Selection_11 1.00 root like(planner__core__range_scan_for_like.t.a, "", 92) + └─Point_Get_10 1.00 root table:t, index:ia(a) 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%dd", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\x0e3\x0e3","\x0e3\x0e4"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa%%dd", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\x0e3\x0e3","\x0e3\x0e4"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa_bccdd", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\x0e3\x0e3","\x0e3\x0e4"), 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 @@ -378,46 +376,46 @@ aabbccdd 8 测试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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %%", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["","\x02\n"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %%语言", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["","\x02\n"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 %", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\x02\t\x02\t\xfbA\x8b\xed","\x02\t\x02\t\xfbA\x8b\xed\x02\n"), 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, Column#3->Column#5 +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─Projection_9 250.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 250.00 root index:Selection_11 + └─Selection_11 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 _", 92) + └─IndexRangeScan_10 250.00 cop[tikv] table:t, index:ia(a) range:["\x02\t\x02\t\xfbA\x8b\xed","\x02\t\x02\t\xfbA\x8b\xed\x02\t\x02\n"), 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; @@ -435,44 +433,44 @@ insert into t (a, b, c) values ('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 +Sort_5 6.25 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 6.25 root data:Selection_9 + └─Selection_9 6.25 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%", 92), like(planner__core__range_scan_for_like.t.b, "asd%", 92) + └─TableRangeScan_8 250.00 cop[tikv] table:t range:["\xfb@\xedK","\xfb@\xedL"), 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 +Sort_5 0.25 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 0.25 root data:Selection_9 + └─Selection_9 0.25 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试1", 92), like(planner__core__range_scan_for_like.t.b, "asdfgh %", 92) + └─TableRangeScan_8 10.00 cop[tikv] table:t range:["\xfb@\xedK","\xfb@\xedK"], 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 +Sort_5 6.25 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 6.25 root data:Selection_9 + └─Selection_9 6.25 cop[tikv] like(planner__core__range_scan_for_like.t.a, "こんにち_", 92), like(planner__core__range_scan_for_like.t.b, "zxc%", 92) + └─TableRangeScan_8 250.00 cop[tikv] table:t range:["=d","=e"), 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 +Sort_5 6.25 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─TableReader_10 6.25 root data:Selection_9 + └─Selection_9 6.25 cop[tikv] like(planner__core__range_scan_for_like.t.a, "안녕하세요%", 92), like(planner__core__range_scan_for_like.t.b, "asd%", 92) + └─TableRangeScan_8 250.00 cop[tikv] table:t range:["<\x00 'aabb' order by a,_tidb_rowid; @@ -684,7 +682,7 @@ 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 + ├─IndexRangeScan_9(Build) 3333.33 cop[tikv] table:t, index:ia(a, b) range:["\x00A\x00A\x00B",+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; @@ -702,7 +700,7 @@ 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 + ├─IndexRangeScan_9(Build) 3333.33 cop[tikv] table:t, index:ia(a, b) range:("\x00A\x00A",+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; @@ -721,7 +719,7 @@ 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 + ├─IndexRangeScan_9(Build) 3323.33 cop[tikv] table:t, index:ia(a, b) range:[-inf,"\x00A\x00A\x00B"], 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; @@ -739,7 +737,7 @@ 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 + ├─IndexRangeScan_9(Build) 3323.33 cop[tikv] table:t, index:ia(a, b) range:[-inf,"\x00A\x00A\x00B"), 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; @@ -756,7 +754,7 @@ 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 + ├─IndexRangeScan_9(Build) 3323.33 cop[tikv] table:t, index:ia(a, b) range:[-inf,"\x00A\x00A"), 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; @@ -772,7 +770,7 @@ 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 + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a, b) 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; @@ -797,7 +795,7 @@ 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 + ├─IndexFullScan_9(Build) 10000.00 cop[tikv] table:t, index:ia(a, b) 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; @@ -820,12 +818,12 @@ aABBccdd 890 测试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 +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, b) range:["mK\x8b\xd5\x00A","mK\x8b\xd5\x00A"], keep order:false, stats:pseudo + └─Selection_11(Probe) 10.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试abc", 92) + └─TableRowIDScan_10 10.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 @@ -834,7 +832,7 @@ 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 + ├─IndexRangeScan_9(Build) 10.00 cop[tikv] table:t, index:ia(a, b) range:["mK\x8b\xd5\x00A","mK\x8b\xd5\x00A"], 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; @@ -842,12 +840,12 @@ 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 +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, b) range:["\x00A\x00A","\x00A\x00A"], keep order:false, stats:pseudo + └─Selection_11(Probe) 10.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "aa", 92) + └─TableRowIDScan_10 10.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 @@ -856,7 +854,7 @@ 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 + ├─IndexRangeScan_9(Build) 10.00 cop[tikv] table:t, index:ia(a, b) range:["\x00A\x00A","\x00A\x00A"], 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; @@ -864,12 +862,12 @@ 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 +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, b) range:["mKmK\x8b\xd5","mKmK\x8b\xd5"], keep order:false, stats:pseudo + └─Selection_11(Probe) 10.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测测试 ", 92) + └─TableRowIDScan_10 10.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 @@ -878,7 +876,7 @@ 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 + ├─IndexRangeScan_9(Build) 10.00 cop[tikv] table:t, index:ia(a, b) range:["mKmK\x8b\xd5","mKmK\x8b\xd5"], 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; @@ -887,12 +885,12 @@ a b 测测试 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 +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, b) range:["\x00 \x00 \x8b\xed","\x00 \x00 \x8b\xed"], keep order:false, stats:pseudo + └─Selection_11(Probe) 10.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语 言", 92) + └─TableRowIDScan_10 10.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 @@ -901,7 +899,7 @@ 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 + ├─IndexRangeScan_9(Build) 10.00 cop[tikv] table:t, index:ia(a, b) range:["\x00 \x00 \x8b\xed","\x00 \x00 \x8b\xed"], 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; @@ -909,12 +907,12 @@ 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 250.00 root + ├─IndexRangeScan_9(Build) 250.00 cop[tikv] table:t, index:ia(a, b) range:["mK\x8b\xd5","mK\x8b\xd6"), keep order:false, stats:pseudo + └─Selection_11(Probe) 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试%", 92) + └─TableRowIDScan_10 250.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 @@ -922,78 +920,116 @@ 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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 250.00 root + ├─IndexRangeScan_9(Build) 250.00 cop[tikv] table:t, index:ia(a, b) range:["mK","mL"), keep order:false, stats:pseudo + └─Selection_11(Probe) 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测_", 92) + └─TableRowIDScan_10 250.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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 250.00 root + ├─IndexRangeScan_9(Build) 250.00 cop[tikv] table:t, index:ia(a, b) range:["mKmK\x8b\xd5","mKmK\x8b\xd6"), keep order:false, stats:pseudo + └─Selection_11(Probe) 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测测试 %", 92) + └─TableRowIDScan_10 250.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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 250.00 root + ├─IndexRangeScan_9(Build) 250.00 cop[tikv] table:t, index:ia(a, b) range:["mK\x8b\xd5\x00A","mK\x8b\xd5\x00B"), keep order:false, stats:pseudo + └─Selection_11(Probe) 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试a__", 92) + └─TableRowIDScan_10 250.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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 250.00 root + ├─IndexRangeScan_9(Build) 250.00 cop[tikv] table:t, index:ia(a, b) range:["mK\x8b\xd5","mK\x8b\xd5\x00!"), keep order:false, stats:pseudo + └─Selection_11(Probe) 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, "测试 __", 92) + └─TableRowIDScan_10 250.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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 250.00 root + ├─IndexRangeScan_9(Build) 250.00 cop[tikv] table:t, index:ia(a, b) range:["","\x00!"), keep order:false, stats:pseudo + └─Selection_11(Probe) 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " _", 92) + └─TableRowIDScan_10 250.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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 250.00 root + ├─IndexRangeScan_9(Build) 250.00 cop[tikv] table:t, index:ia(a, b) range:["","\x00 \x00 \x00!"), keep order:false, stats:pseudo + └─Selection_11(Probe) 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " %", 92) + └─TableRowIDScan_10 250.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 +Projection_6 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 250.00 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 250.00 root + ├─IndexRangeScan_9(Build) 250.00 cop[tikv] table:t, index:ia(a, b) range:["\x00 \x8b\xed\x8a\x00","\x00 \x8b\xed\x8a\x01"), keep order:false, stats:pseudo + └─Selection_11(Probe) 250.00 cop[tikv] like(planner__core__range_scan_for_like.t.a, " 语言%%", 92) + └─TableRowIDScan_10 250.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 +explain select * from t use index (ia) where a not in ('aabc','dd') order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 3583.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 3583.33 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_12 3583.33 root + ├─IndexRangeScan_9(Build) 3583.33 cop[tikv] table:t, index:ia(a, b) range:(NULL,"\x00D\x00D"), ("\x00D\x00D",+inf], keep order:false, stats:pseudo + └─Selection_11(Probe) 3583.33 cop[tikv] not(in(planner__core__range_scan_for_like.t.a, "aabc", "dd")) + └─TableRowIDScan_10 3583.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index (ia) where a not in ('aabc','dd') 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 where a >= 'aabb' and a <= 'aabd' and b = 456 order by a,_tidb_rowid; +id estRows task access object operator info +Projection_6 0.01 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t.b +└─Sort_7 0.01 root planner__core__range_scan_for_like.t.a, planner__core__range_scan_for_like.t._tidb_rowid + └─IndexLookUp_16 0.01 root + ├─Selection_14(Build) 0.01 cop[tikv] eq(planner__core__range_scan_for_like.t.b, 456) + │ └─IndexRangeScan_12 10.00 cop[tikv] table:t, index:ia(a, b) range:["\x00A\x00A\x00B","\x00A\x00A\x00B"], keep order:false, stats:pseudo + └─Selection_15(Probe) 0.01 cop[tikv] ge(planner__core__range_scan_for_like.t.a, "aabb"), le(planner__core__range_scan_for_like.t.a, "aabd") + └─TableRowIDScan_13 0.01 cop[tikv] table:t keep order:false, stats:pseudo +select * from t where a >= 'aabb' and a <= 'aabd' and b = 456 order by a,_tidb_rowid; +a b +aabB 456 diff --git a/tests/integrationtest/t/planner/core/range_scan_for_like.test b/tests/integrationtest/t/planner/core/range_scan_for_like.test index c6113bc053bfe..ff60df3f17584 100644 --- a/tests/integrationtest/t/planner/core/range_scan_for_like.test +++ b/tests/integrationtest/t/planner/core/range_scan_for_like.test @@ -158,7 +158,7 @@ explain select * from t use index (primary) where a like ' %' and b like '123%' 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))); +create table t(a varchar(20) collate utf8mb4_general_ci, b bigint, index ia(a(3),b)); insert into t value ('测试',222), ('测试Abc',324), @@ -225,19 +225,7 @@ explain select * from t use index (ia) where a like ' %' order by a,_tidb_row 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 not in ('aabc','dd') order by a,_tidb_rowid; +select * from t use index (ia) where a not in ('aabc','dd') order by a,_tidb_rowid; +explain select * from t where a >= 'aabb' and a <= 'aabd' and b = 456 order by a,_tidb_rowid; +select * from t where a >= 'aabb' and a <= 'aabd' and b = 456 order by a,_tidb_rowid;