planner: derive index filters for mv index paths (#54877)
close pingcap/tidb#54876
This commit is contained in:
@ -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
|
||||
|
||||
@ -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%';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user