planner: derive index filters for mv index paths (#54877)

close pingcap/tidb#54876
This commit is contained in:
Zhou Kunqin
2024-07-27 01:26:44 +08:00
committed by GitHub
parent 197476a41d
commit 56710aeaef
3 changed files with 261 additions and 4 deletions

View File

@ -1081,3 +1081,127 @@ IndexMerge 0.05 root type: union
└─Selection(Probe) 0.05 cop[tikv] eq(planner__core__indexmerge_path.t.a, 1)
└─TableRowIDScan 49.94 cop[tikv] table:t keep order:false, stats:pseudo
SET @@tidb_opt_fix_control = default;
drop table if exists t, t1;
create table t (a int, b varchar(30), c float, j json, pk int primary key,
key mvi1(c, (cast(j->'$.a' as unsigned array)), b),
key mvi2(a, (cast(j->'$.c' as unsigned array))),
key mvi3((cast(j->'$.d' as unsigned array)), c),
key idx(b, c)
);
insert into t values (1, 'test', 1, '{"a":[3,4,5], "c":[7,8,9], "d":[10,11,12]}', 1);
insert into t values (2, 'text', 1, '{"a":[4,5,6], "c":[10,11,12], "d":[13,14,15]}', 2);
insert into t values (1, 'abcd', 1, '{"a":[7,8,9], "c":[13,14,15], "d":[16,17,18]}', 3);
SELECT /*+ use_index_merge(t, mvi1) */ * from t where
c = 1 and
json_overlaps(j->'$.a', '[4,5,6]') and
b not like '%test%';
a b c j pk
2 text 1 {"a": [4, 5, 6], "c": [10, 11, 12], "d": [13, 14, 15]} 2
EXPLAIN format = brief SELECT /*+ use_index_merge(t, mvi1) */ * from t where
c = 1 and
json_overlaps(j->'$.a', '[4,5,6]') and
b not like '%test%';
id estRows task access object operator info
Selection 0.24 root json_overlaps(json_extract(planner__core__indexmerge_path.t.j, "$.a"), cast("[4,5,6]", json BINARY))
└─IndexMerge 0.30 root type: union
├─Selection(Build) 0.00 cop[tikv] not(like(planner__core__indexmerge_path.t.b, "%test%", 92))
│ └─IndexRangeScan 0.10 cop[tikv] table:t, index:mvi1(c, cast(json_extract(`j`, _utf8mb4'$.a') as unsigned array), b) range:[1 4,1 4], keep order:false, stats:pseudo
├─Selection(Build) 0.00 cop[tikv] not(like(planner__core__indexmerge_path.t.b, "%test%", 92))
│ └─IndexRangeScan 0.10 cop[tikv] table:t, index:mvi1(c, cast(json_extract(`j`, _utf8mb4'$.a') as unsigned array), b) range:[1 5,1 5], keep order:false, stats:pseudo
├─Selection(Build) 0.00 cop[tikv] not(like(planner__core__indexmerge_path.t.b, "%test%", 92))
│ └─IndexRangeScan 0.10 cop[tikv] table:t, index:mvi1(c, cast(json_extract(`j`, _utf8mb4'$.a') as unsigned array), b) range:[1 6,1 6], keep order:false, stats:pseudo
└─TableRowIDScan(Probe) 0.30 cop[tikv] table:t keep order:false, stats:pseudo
SELECT /*+ use_index_merge(t, mvi1) */ * from t where
c = 1 and
json_contains(j->'$.a', '[4,5]') and
b not like '%test%';
a b c j pk
2 text 1 {"a": [4, 5, 6], "c": [10, 11, 12], "d": [13, 14, 15]} 2
EXPLAIN format = brief SELECT /*+ use_index_merge(t, mvi1) */ * from t where
c = 1 and
json_contains(j->'$.a', '[4,5]') and
b not like '%test%';
id estRows task access object operator info
IndexMerge 0.00 root type: intersection
├─Selection(Build) 0.00 cop[tikv] not(like(planner__core__indexmerge_path.t.b, "%test%", 92))
│ └─IndexRangeScan 0.10 cop[tikv] table:t, index:mvi1(c, cast(json_extract(`j`, _utf8mb4'$.a') as unsigned array), b) range:[1 4,1 4], keep order:false, stats:pseudo
├─Selection(Build) 0.00 cop[tikv] not(like(planner__core__indexmerge_path.t.b, "%test%", 92))
│ └─IndexRangeScan 0.10 cop[tikv] table:t, index:mvi1(c, cast(json_extract(`j`, _utf8mb4'$.a') as unsigned array), b) range:[1 5,1 5], keep order:false, stats:pseudo
└─TableRowIDScan(Probe) 0.00 cop[tikv] table:t keep order:false, stats:pseudo
SELECT /*+ use_index_merge(t, mvi1, mvi2, idx) */ * from t where
a = 1 and
b > 'abc' and
b not like '%test%' and
c = 10 and
3 member of (j->'$.a') and
3 member of (j->'$.c');
a b c j pk
EXPLAIN format=brief SELECT /*+ use_index_merge(t, mvi1, mvi2, idx) */ * from t where
a = 1 and
b > 'abc' and
b not like '%test%' and
c = 10 and
3 member of (j->'$.a') and
3 member of (j->'$.c');
id estRows task access object operator info
IndexMerge 0.00 root type: intersection
├─Selection(Build) 2.67 cop[tikv] eq(planner__core__indexmerge_path.t.c, 10), not(like(planner__core__indexmerge_path.t.b, "%test%", 92)), not(like(planner__core__indexmerge_path.t.b, "%test%", 92))
│ └─IndexRangeScan 3333.33 cop[tikv] table:t, index:idx(b, c) range:("abc",+inf], keep order:false, stats:pseudo
├─Selection(Build) 0.00 cop[tikv] not(like(planner__core__indexmerge_path.t.b, "%test%", 92))
│ └─IndexRangeScan 0.10 cop[tikv] table:t, index:mvi1(c, cast(json_extract(`j`, _utf8mb4'$.a') as unsigned array), b) range:[10 3,10 3], keep order:false, stats:pseudo
├─IndexRangeScan(Build) 0.10 cop[tikv] table:t, index:mvi2(a, cast(json_extract(`j`, _utf8mb4'$.c') as unsigned array)) range:[1 3,1 3], keep order:false, stats:pseudo
└─TableRowIDScan(Probe) 0.00 cop[tikv] table:t keep order:false, stats:pseudo
create table t1 (
a int,
b varchar(30),
c float,
d tinytext,
j json,
key mvi1(b(3), (cast(j as unsigned array))),
key mvi2((cast(j as unsigned array)), b),
key mvi3((cast(j as unsigned array)), d(30)),
key mvi4((cast(j as unsigned array)), d(255))
);
EXPLAIN format = brief SELECT /*+ use_index_merge(t1, mvi1) */ * from t1 where
c = 1 and
json_contains(j, '[4,5]') and
b = 'abcdefg';
id estRows task access object operator info
TableReader 0.00 root data:Selection
└─Selection 0.00 cop[tikv] eq(planner__core__indexmerge_path.t1.b, "abcdefg"), eq(planner__core__indexmerge_path.t1.c, 1), json_contains(planner__core__indexmerge_path.t1.j, cast("[4,5]", json BINARY))
└─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo
EXPLAIN format = brief SELECT /*+ use_index_merge(t1, mvi2) */ * from t1 where
c = 1 and
json_contains(j, '[4,5]') and
b = 'abcdefg' and
b like '%test%';
id estRows task access object operator info
IndexMerge 0.00 root type: intersection
├─Selection(Build) 0.00 cop[tikv] like(planner__core__indexmerge_path.t1.b, "%test%", 92)
│ └─IndexRangeScan 0.10 cop[tikv] table:t1, index:mvi2(cast(`j` as unsigned array), b) range:[4 "abcdefg",4 "abcdefg"], keep order:false, stats:pseudo
├─Selection(Build) 0.00 cop[tikv] like(planner__core__indexmerge_path.t1.b, "%test%", 92)
│ └─IndexRangeScan 0.10 cop[tikv] table:t1, index:mvi2(cast(`j` as unsigned array), b) range:[5 "abcdefg",5 "abcdefg"], keep order:false, stats:pseudo
└─Selection(Probe) 0.00 cop[tikv] eq(planner__core__indexmerge_path.t1.c, 1)
└─TableRowIDScan 0.00 cop[tikv] table:t1 keep order:false, stats:pseudo
EXPLAIN format = brief SELECT /*+ use_index_merge(t1, mvi3) */ * from t1 where
c = 1 and
json_contains(j, '[4,5]') and
d not like '%test%';
id estRows task access object operator info
IndexMerge 0.01 root type: intersection
├─IndexRangeScan(Build) 10.00 cop[tikv] table:t1, index:mvi3(cast(`j` as unsigned array), d) range:[4,4], keep order:false, stats:pseudo
├─IndexRangeScan(Build) 10.00 cop[tikv] table:t1, index:mvi3(cast(`j` as unsigned array), d) range:[5,5], keep order:false, stats:pseudo
└─Selection(Probe) 0.01 cop[tikv] eq(planner__core__indexmerge_path.t1.c, 1), not(like(planner__core__indexmerge_path.t1.d, "%test%", 92))
└─TableRowIDScan 0.01 cop[tikv] table:t1 keep order:false, stats:pseudo
EXPLAIN format = brief SELECT /*+ use_index_merge(t1, mvi4) */ * from t1 where
c = 1 and
json_contains(j, '[4,5]') and
d not like '%test%';
id estRows task access object operator info
IndexMerge 0.01 root type: intersection
├─Selection(Build) 0.00 cop[tikv] not(like(planner__core__indexmerge_path.t1.d, "%test%", 92))
│ └─IndexRangeScan 10.00 cop[tikv] table:t1, index:mvi4(cast(`j` as unsigned array), d) range:[4,4], keep order:false, stats:pseudo
├─Selection(Build) 0.00 cop[tikv] not(like(planner__core__indexmerge_path.t1.d, "%test%", 92))
│ └─IndexRangeScan 10.00 cop[tikv] table:t1, index:mvi4(cast(`j` as unsigned array), d) range:[5,5], keep order:false, stats:pseudo
└─Selection(Probe) 0.01 cop[tikv] eq(planner__core__indexmerge_path.t1.c, 1)
└─TableRowIDScan 0.01 cop[tikv] table:t1 keep order:false, stats:pseudo

View File

@ -425,3 +425,91 @@ EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b =
EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b = '4' OR c = 5 OR b = '12' OR c = 13);
EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (c = 13 OR c = 15 OR c = 5 OR b = '12' OR c = 13 OR b = '11');
SET @@tidb_opt_fix_control = default;
# Test deriving index filters for mv index paths
drop table if exists t, t1;
create table t (a int, b varchar(30), c float, j json, pk int primary key,
key mvi1(c, (cast(j->'$.a' as unsigned array)), b),
key mvi2(a, (cast(j->'$.c' as unsigned array))),
key mvi3((cast(j->'$.d' as unsigned array)), c),
key idx(b, c)
);
insert into t values (1, 'test', 1, '{"a":[3,4,5], "c":[7,8,9], "d":[10,11,12]}', 1);
insert into t values (2, 'text', 1, '{"a":[4,5,6], "c":[10,11,12], "d":[13,14,15]}', 2);
insert into t values (1, 'abcd', 1, '{"a":[7,8,9], "c":[13,14,15], "d":[16,17,18]}', 3);
# case 1: union type index merge on single mv index from single condition
SELECT /*+ use_index_merge(t, mvi1) */ * from t where
c = 1 and
json_overlaps(j->'$.a', '[4,5,6]') and
b not like '%test%';
EXPLAIN format = brief SELECT /*+ use_index_merge(t, mvi1) */ * from t where
c = 1 and
json_overlaps(j->'$.a', '[4,5,6]') and
b not like '%test%';
# case 2: intersection type index merge on single mv index from single condition
SELECT /*+ use_index_merge(t, mvi1) */ * from t where
c = 1 and
json_contains(j->'$.a', '[4,5]') and
b not like '%test%';
EXPLAIN format = brief SELECT /*+ use_index_merge(t, mvi1) */ * from t where
c = 1 and
json_contains(j->'$.a', '[4,5]') and
b not like '%test%';
# case 3: intersection type index merge on multiple indexes from different conditions
SELECT /*+ use_index_merge(t, mvi1, mvi2, idx) */ * from t where
a = 1 and
b > 'abc' and
b not like '%test%' and
c = 10 and
3 member of (j->'$.a') and
3 member of (j->'$.c');
EXPLAIN format=brief SELECT /*+ use_index_merge(t, mvi1, mvi2, idx) */ * from t where
a = 1 and
b > 'abc' and
b not like '%test%' and
c = 10 and
3 member of (j->'$.a') and
3 member of (j->'$.c');
# case 4: test prefix indexes
create table t1 (
a int,
b varchar(30),
c float,
d tinytext,
j json,
key mvi1(b(3), (cast(j as unsigned array))),
key mvi2((cast(j as unsigned array)), b),
key mvi3((cast(j as unsigned array)), d(30)),
key mvi4((cast(j as unsigned array)), d(255))
);
EXPLAIN format = brief SELECT /*+ use_index_merge(t1, mvi1) */ * from t1 where
c = 1 and
json_contains(j, '[4,5]') and
b = 'abcdefg';
EXPLAIN format = brief SELECT /*+ use_index_merge(t1, mvi2) */ * from t1 where
c = 1 and
json_contains(j, '[4,5]') and
b = 'abcdefg' and
b like '%test%';
EXPLAIN format = brief SELECT /*+ use_index_merge(t1, mvi3) */ * from t1 where
c = 1 and
json_contains(j, '[4,5]') and
d not like '%test%';
EXPLAIN format = brief SELECT /*+ use_index_merge(t1, mvi4) */ * from t1 where
c = 1 and
json_contains(j, '[4,5]') and
d not like '%test%';