From f257590afc01817c3aacd8b87ec5031d4a06aa13 Mon Sep 17 00:00:00 2001 From: Arenatlx <314806019@qq.com> Date: Fri, 12 Jan 2024 17:00:25 +0800 Subject: [PATCH] planner: fix union index merge can merge a embedded intersection index merge with only one partial path (#50363) close pingcap/tidb#50265 --- pkg/planner/core/indexmerge_path.go | 8 ++++++-- .../r/planner/core/casetest/index/index.result | 15 +++++++++++++++ .../t/planner/core/casetest/index/index.test | 7 ++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/pkg/planner/core/indexmerge_path.go b/pkg/planner/core/indexmerge_path.go index 5fe5f9f17696b..9acb0ffc54d08 100644 --- a/pkg/planner/core/indexmerge_path.go +++ b/pkg/planner/core/indexmerge_path.go @@ -705,10 +705,14 @@ func (ds *DataSource) generateMVIndexPartialPath4Or(normalPathCnt int, indexMerg logutil.BgLogger().Debug("build index merge partial mv index paths failed", zap.Error(err)) return nil, nil, false, err } - if isIntersection || !ok { // limitation 2 + if !ok || len(paths) == 0 { continue } - if len(paths) == 0 { + // only under 2 cases we can fallthrough it. + // 1: the index merge only has one partial path. + // 2: index merge is UNION type. + canFallThrough := len(paths) == 1 || !isIntersection + if !canFallThrough { continue } // UNION case, use the max count after access for simplicity. diff --git a/tests/integrationtest/r/planner/core/casetest/index/index.result b/tests/integrationtest/r/planner/core/casetest/index/index.result index 43eb6d11c0637..541ea9ee62150 100644 --- a/tests/integrationtest/r/planner/core/casetest/index/index.result +++ b/tests/integrationtest/r/planner/core/casetest/index/index.result @@ -797,3 +797,18 @@ a b c d 1 111 1.1000000000 11 3 333 3.3000000000 13 set tidb_enable_clustered_index=default; +drop table if exists t; +create table t(item_primary_key varbinary(255) NOT NULL, domains json null, image_signatures json null, canonical_links json null, feed_profile_ids json null, KEY `domains` ((cast(`domains` as char(253) array))), KEY `image_signatures` ((cast(`image_signatures` as char(32) array))),KEY `canonical_links` ((cast(`canonical_links` as char(1000) array))), KEY `feed_profile_ids` ((cast(`feed_profile_ids` as unsigned array)))); +explain SELECT item_primary_key FROM t WHERE "B2c32" member of (domains) OR "2eoqyp6399" member of (image_signatures) OR "E33EAdAc2Bee.com/s/link" member of (canonical_links) OR json_contains(feed_profile_ids, '[69236881]') LIMIT 10; +id estRows task access object operator info +Projection_24 10.00 root planner__core__casetest__index__index.t.item_primary_key +└─IndexMerge_23 10.00 root type: union, limit embedded(offset:0, count:10) + ├─Limit_19(Build) 2.50 cop[tikv] offset:0, count:10 + │ └─IndexRangeScan_14 2.50 cop[tikv] table:t, index:domains(cast(`domains` as char(253) array)) range:["B2c32","B2c32"], keep order:false, stats:pseudo + ├─Limit_20(Build) 2.50 cop[tikv] offset:0, count:10 + │ └─IndexRangeScan_15 2.50 cop[tikv] table:t, index:image_signatures(cast(`image_signatures` as char(32) array)) range:["2eoqyp6399","2eoqyp6399"], keep order:false, stats:pseudo + ├─Limit_21(Build) 2.50 cop[tikv] offset:0, count:10 + │ └─IndexRangeScan_16 2.50 cop[tikv] table:t, index:canonical_links(cast(`canonical_links` as char(1000) array)) range:["E33EAdAc2Bee.com/s/link","E33EAdAc2Bee.com/s/link"], keep order:false, stats:pseudo + ├─Limit_22(Build) 2.50 cop[tikv] offset:0, count:10 + │ └─IndexRangeScan_17 2.50 cop[tikv] table:t, index:feed_profile_ids(cast(`feed_profile_ids` as unsigned array)) range:[69236881,69236881], keep order:false, stats:pseudo + └─TableRowIDScan_18(Probe) 10.00 cop[tikv] table:t keep order:false, stats:pseudo diff --git a/tests/integrationtest/t/planner/core/casetest/index/index.test b/tests/integrationtest/t/planner/core/casetest/index/index.test index 93584464f867b..f61560a1527a1 100644 --- a/tests/integrationtest/t/planner/core/casetest/index/index.test +++ b/tests/integrationtest/t/planner/core/casetest/index/index.test @@ -29,7 +29,6 @@ explain select /*+ use_index_merge(t2, idx2, idx) */ * from t2 where (1 member o explain select /*+ use_index_merge(t2, idx2, idx) */ * from t2 where (1 member of (a) and 1 member of (b) and c=3) or (3 member of (b) and c=4) or e=1; -- 8: OR index merge from multi complicated mv index (memberof), each DNF item should be strict or lax used as index partial path.; explain select /*+ use_index_merge(t2, idx2, idx, idx4) */ * from t2 where (1 member of (a) and 1 member of (b) and c=3) or (3 member of (b) and c=4) or d=1; -- 9: OR index merge from multi complicated mv index (memberof), each DNF item should be strict or lax used as index partial path, specify the index in index merge hint; - # TestIndexMergeFromComposedCNFCondition drop table if exists t1, t2; create table t1(pk int primary key, a json, b json, c int, d int, index idx((cast(a as signed array))), index idx2((cast(b as signed array)))); @@ -273,3 +272,9 @@ explain format='brief' select /*+ use_index_merge(t1 primary, c) */ * from t1 wh --sorted_result select /*+ use_index_merge(t1 primary, c) */ * from t1 where t1.a = 1 and t1.b = '111' or t1.c = 3.3; set tidb_enable_clustered_index=default; + +# TestIndexMergeIssue50265 +drop table if exists t; +create table t(item_primary_key varbinary(255) NOT NULL, domains json null, image_signatures json null, canonical_links json null, feed_profile_ids json null, KEY `domains` ((cast(`domains` as char(253) array))), KEY `image_signatures` ((cast(`image_signatures` as char(32) array))),KEY `canonical_links` ((cast(`canonical_links` as char(1000) array))), KEY `feed_profile_ids` ((cast(`feed_profile_ids` as unsigned array)))); +explain SELECT item_primary_key FROM t WHERE "B2c32" member of (domains) OR "2eoqyp6399" member of (image_signatures) OR "E33EAdAc2Bee.com/s/link" member of (canonical_links) OR json_contains(feed_profile_ids, '[69236881]') LIMIT 10; +