diff --git a/pkg/planner/core/exhaust_physical_plans.go b/pkg/planner/core/exhaust_physical_plans.go index 785498491f663..6ce8bdea34106 100644 --- a/pkg/planner/core/exhaust_physical_plans.go +++ b/pkg/planner/core/exhaust_physical_plans.go @@ -710,6 +710,9 @@ func (p *LogicalJoin) constructIndexHashJoin( path *util.AccessPath, compareFilters *ColWithCmpFuncManager, ) []PhysicalPlan { + if strings.HasPrefix(p.SCtx().GetSessionVars().StmtCtx.OriginalSQL, "select * from tdbe45f5c t1 join (select * from `teef726a5`") { + fmt.Println(1) + } indexJoins := p.constructIndexJoin(prop, outerIdx, innerTask, ranges, keyOff2IdxOff, path, compareFilters, true) indexHashJoins := make([]PhysicalPlan, 0, len(indexJoins)) for _, plan := range indexJoins { @@ -959,7 +962,21 @@ func (p *LogicalJoin) buildIndexJoinInner2IndexScan( outerIdx int, avgInnerRowCnt float64) (joins []PhysicalPlan) { ds := wrapper.ds us := wrapper.us - helper, keyOff2IdxOff := p.getIndexJoinBuildHelper(ds, innerJoinKeys, func(path *util.AccessPath) bool { return !path.IsTablePath() }, outerJoinKeys) + indexValid := func(path *util.AccessPath) bool { + if path.IsTablePath() { + return false + } + // if path is index path. index path currently include two kind of, one is normal, and the other is mv index. + // for mv index like mvi(a, json, b), if driving condition is a=1, and we build a prefix scan with range [1,1] + // on mvi, it will return many index rows which breaks handle-unique attribute here. + // + // the basic rule is that: mv index can be and can only be accessed by indexMerge operator. (embedded handle duplication) + if !isMVIndexPath(path) { + return true // not a MVIndex path, it can successfully be index join probe side. + } + return false + } + helper, keyOff2IdxOff := p.getIndexJoinBuildHelper(ds, innerJoinKeys, indexValid, outerJoinKeys) if helper == nil { return nil } diff --git a/tests/integrationtest/r/planner/core/casetest/index/index.result b/tests/integrationtest/r/planner/core/casetest/index/index.result index 541ea9ee62150..a73cb86288b2d 100644 --- a/tests/integrationtest/r/planner/core/casetest/index/index.result +++ b/tests/integrationtest/r/planner/core/casetest/index/index.result @@ -812,3 +812,18 @@ Projection_24 10.00 root planner__core__casetest__index__index.t.item_primary_k ├─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 +drop table if exists t1, t2; +CREATE TABLE `t1` (`a` varchar(488) COLLATE utf8_general_ci DEFAULT NULL, `b` binary(206) DEFAULT '0', `c` json DEFAULT NULL, UNIQUE KEY `idx_29` (`a`,(cast(`c` as signed array)),`b`), UNIQUE KEY `idx_30` ((cast(`c` as signed array)),`a`(5))) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; +CREATE TABLE `t2` (`a` float NOT NULL DEFAULT '5217.6055',`b` json NOT NULL,`c` json NOT NULL,`d` varchar(181) COLLATE gbk_bin NOT NULL DEFAULT 'FbVkA~^', KEY `idx_26` (`a`),PRIMARY KEY (`a`,`d`) /*T![clustered_index] NONCLUSTERED */,UNIQUE KEY `idx_28` (`a`,(cast(`b` as binary(64) array)),`d`)) ENGINE=InnoDB DEFAULT CHARSET=gbk COLLATE=gbk_bin; +EXPLAIN SELECT /*+ inl_join(t1)*/ `t2`.`c` AS `r0` FROM `t1` JOIN `t2` ON `t1`.`a`=`t2`.`d` WHERE `t2`.`d`='' AND NOT (6252179388429456273 MEMBER OF (`t1`.`c`)); +id estRows task access object operator info +HashJoin_12 12.50 root inner join, equal:[eq(planner__core__casetest__index__index.t2.d, planner__core__casetest__index__index.t1.a)] +├─TableReader_15(Build) 10.00 root data:Selection_14 +│ └─Selection_14 10.00 cop[tikv] eq(planner__core__casetest__index__index.t2.d, "") +│ └─TableFullScan_13 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo +└─TableReader_18(Probe) 7992.00 root data:Selection_17 + └─Selection_17 7992.00 cop[tikv] not(isnull(planner__core__casetest__index__index.t1.a)), not(istrue_with_null(json_memberof(cast(6252179388429456273, json BINARY), planner__core__casetest__index__index.t1.c))) + └─TableFullScan_16 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo +SHOW WARNINGS +Level Code Message +Warning 1815 Optimizer Hint /*+ INL_JOIN(t1) */ or /*+ TIDB_INLJ(t1) */ is inapplicable diff --git a/tests/integrationtest/t/planner/core/casetest/index/index.test b/tests/integrationtest/t/planner/core/casetest/index/index.test index f61560a1527a1..c5d024a9b2c81 100644 --- a/tests/integrationtest/t/planner/core/casetest/index/index.test +++ b/tests/integrationtest/t/planner/core/casetest/index/index.test @@ -278,3 +278,10 @@ 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; +# TestIndexMergeIssue50382 +drop table if exists t1, t2; +CREATE TABLE `t1` (`a` varchar(488) COLLATE utf8_general_ci DEFAULT NULL, `b` binary(206) DEFAULT '0', `c` json DEFAULT NULL, UNIQUE KEY `idx_29` (`a`,(cast(`c` as signed array)),`b`), UNIQUE KEY `idx_30` ((cast(`c` as signed array)),`a`(5))) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; +CREATE TABLE `t2` (`a` float NOT NULL DEFAULT '5217.6055',`b` json NOT NULL,`c` json NOT NULL,`d` varchar(181) COLLATE gbk_bin NOT NULL DEFAULT 'FbVkA~^', KEY `idx_26` (`a`),PRIMARY KEY (`a`,`d`) /*T![clustered_index] NONCLUSTERED */,UNIQUE KEY `idx_28` (`a`,(cast(`b` as binary(64) array)),`d`)) ENGINE=InnoDB DEFAULT CHARSET=gbk COLLATE=gbk_bin; +EXPLAIN SELECT /*+ inl_join(t1)*/ `t2`.`c` AS `r0` FROM `t1` JOIN `t2` ON `t1`.`a`=`t2`.`d` WHERE `t2`.`d`='' AND NOT (6252179388429456273 MEMBER OF (`t1`.`c`)); +SHOW WARNINGS +