diff --git a/pkg/ddl/executor.go b/pkg/ddl/executor.go index 5c264a51fce1f..f50c0e7bb239d 100644 --- a/pkg/ddl/executor.go +++ b/pkg/ddl/executor.go @@ -961,15 +961,6 @@ func checkGlobalIndex(ec errctx.Context, tblInfo *model.TableInfo, indexInfo *mo if !indexInfo.Unique { return dbterror.ErrGeneralUnsupportedDDL.GenWithStackByArgs("GLOBAL IndexOption on non-unique index") } - // TODO: remove limitation - // check that not all partitioned columns are included. - inAllPartitionColumns, err := checkPartitionKeysConstraint(pi, indexInfo.Columns, tblInfo) - if err != nil { - return errors.Trace(err) - } - if inAllPartitionColumns { - return dbterror.ErrGeneralUnsupportedDDL.GenWithStackByArgs("Global Index including all columns in the partitioning expression") - } validateGlobalIndexWithGeneratedColumns(ec, tblInfo, indexInfo.Name.O, indexInfo.Columns) } return nil @@ -4515,6 +4506,29 @@ func GetName4AnonymousIndex(t table.Table, colName pmodel.CIStr, idxName pmodel. return indexName } +func checkCreateUniqueGlobalIndex(ec errctx.Context, tblInfo *model.TableInfo, indexName string, indexColumns []*model.IndexColumn, isUnique bool, isGlobal bool) error { + pi := tblInfo.GetPartitionInfo() + if isGlobal && pi == nil { + return dbterror.ErrGeneralUnsupportedDDL.GenWithStackByArgs("Global Index on non-partitioned table") + } + if isGlobal && !isUnique { + // TODO: remove this limitation + return dbterror.ErrGeneralUnsupportedDDL.GenWithStackByArgs("Global IndexOption on non-unique index") + } + if isUnique && pi != nil { + ck, err := checkPartitionKeysConstraint(tblInfo.GetPartitionInfo(), indexColumns, tblInfo) + if err != nil { + return err + } + if !ck && !isGlobal { + // index columns does not contain all partition columns, must be global + return dbterror.ErrGlobalIndexNotExplicitlySet.GenWithStackByArgs(indexName) + } + validateGlobalIndexWithGeneratedColumns(ec, tblInfo, indexName, indexColumns) + } + return nil +} + func (e *executor) CreatePrimaryKey(ctx sessionctx.Context, ti ast.Ident, indexName pmodel.CIStr, indexPartSpecifications []*ast.IndexPartSpecification, indexOption *ast.IndexOption) error { if indexOption != nil && indexOption.PrimaryKeyTp == pmodel.PrimaryKeyTypeClustered { @@ -4560,20 +4574,8 @@ func (e *executor) CreatePrimaryKey(ctx sessionctx.Context, ti ast.Ident, indexN return err } - if tblInfo.GetPartitionInfo() != nil { - ck, err := checkPartitionKeysConstraint(tblInfo.GetPartitionInfo(), indexColumns, tblInfo) - if err != nil { - return err - } - if !ck { - // index columns does not contain all partition columns, must be global - if indexOption == nil || !indexOption.Global { - return dbterror.ErrGlobalIndexNotExplicitlySet.GenWithStackByArgs("PRIMARY") - } - validateGlobalIndexWithGeneratedColumns(ctx.GetSessionVars().StmtCtx.ErrCtx(), tblInfo, indexName.O, indexColumns) - } - } else if indexOption != nil && indexOption.Global { - return dbterror.ErrGeneralUnsupportedDDL.GenWithStackByArgs("Global Index on non-partitioned table") + if err = checkCreateUniqueGlobalIndex(ctx.GetSessionVars().StmtCtx.ErrCtx(), tblInfo, "PRIMARY", indexColumns, true, indexOption != nil && indexOption.Global); err != nil { + return err } // May be truncate comment here, when index comment too long and sql_mode is't strict. @@ -4852,35 +4854,10 @@ func (e *executor) createIndex(ctx sessionctx.Context, ti ast.Ident, keyType ast return errors.Trace(err) } - globalIndex := false - if indexOption != nil && indexOption.Global { - globalIndex = true - } - if globalIndex { - if tblInfo.GetPartitionInfo() == nil { - return dbterror.ErrGeneralUnsupportedDDL.GenWithStackByArgs("Global Index on non-partitioned table") - } - if !unique { - // TODO: remove this limitation - return dbterror.ErrGeneralUnsupportedDDL.GenWithStackByArgs("Global IndexOption on non-unique index") - } - } - if unique && tblInfo.GetPartitionInfo() != nil { - ck, err := checkPartitionKeysConstraint(tblInfo.GetPartitionInfo(), indexColumns, tblInfo) - if err != nil { - return err - } - if !ck { - // index columns does not contain all partition columns, must be global - if !globalIndex { - return dbterror.ErrGlobalIndexNotExplicitlySet.GenWithStackByArgs(indexName.O) - } - validateGlobalIndexWithGeneratedColumns(ctx.GetSessionVars().StmtCtx.ErrCtx(), tblInfo, indexName.O, indexColumns) - } else if globalIndex { - // TODO: remove this restriction - return dbterror.ErrGeneralUnsupportedDDL.GenWithStackByArgs("Global IndexOption on index including all columns in the partitioning expression") - } + if err = checkCreateUniqueGlobalIndex(ctx.GetSessionVars().StmtCtx.ErrCtx(), tblInfo, indexName.O, indexColumns, unique, indexOption != nil && indexOption.Global); err != nil { + return err } + // May be truncate comment here, when index comment too long and sql_mode is't strict. if indexOption != nil { sessionVars := ctx.GetSessionVars() diff --git a/tests/integrationtest/r/globalindex/aggregate.result b/tests/integrationtest/r/globalindex/aggregate.result index d0783848d1c86..a665e78cae87f 100644 --- a/tests/integrationtest/r/globalindex/aggregate.result +++ b/tests/integrationtest/r/globalindex/aggregate.result @@ -47,3 +47,25 @@ HashAgg 8000.00 root NULL group by:globalindex__aggregate.p.c, funcs:avg(Column# select avg(id), max(id), min(id) from p partition(p0) use index(idx) group by c; avg(id) max(id) min(id) 1.5000 2 1 +alter table p add unique index idx1(c, id) global; +explain format='brief' select count(*), max(id), min(id) from p use index(idx1); +id estRows task access object operator info +HashAgg 1.00 root funcs:count(Column#10)->Column#4, funcs:max(Column#11)->Column#5, funcs:min(Column#12)->Column#6 +└─IndexReader 1.00 root partition:all index:HashAgg + └─HashAgg 1.00 cop[tikv] funcs:count(1)->Column#10, funcs:max(globalindex__aggregate.p.id)->Column#11, funcs:min(globalindex__aggregate.p.id)->Column#12 + └─IndexFullScan 10000.00 cop[tikv] table:p, index:idx1(c, id) keep order:false, stats:pseudo +select count(*), max(id), min(id) from p use index(idx1); +count(*) max(id) min(id) +7 8 1 +explain format='brief' select avg(id), max(id), min(id) from p use index(idx1) group by c; +id estRows task access object operator info +HashAgg 8000.00 root group by:Column#26, funcs:avg(Column#23)->Column#4, funcs:max(Column#24)->Column#5, funcs:min(Column#25)->Column#6 +└─Projection 10000.00 root cast(globalindex__aggregate.p.id, decimal(10,0) BINARY)->Column#23, globalindex__aggregate.p.id->Column#24, globalindex__aggregate.p.id->Column#25, globalindex__aggregate.p.c->Column#26 + └─IndexReader 10000.00 root partition:all index:IndexFullScan + └─IndexFullScan 10000.00 cop[tikv] table:p, index:idx1(c, id) keep order:false, stats:pseudo +select avg(id), max(id), min(id) from p use index(idx1) group by c; +avg(id) max(id) min(id) +1.5000 2 1 +3.5000 4 3 +5.0000 5 5 +7.5000 8 7 diff --git a/tests/integrationtest/r/globalindex/ddl.result b/tests/integrationtest/r/globalindex/ddl.result index 3d95d2d53eeb1..735d7856b1a03 100644 --- a/tests/integrationtest/r/globalindex/ddl.result +++ b/tests/integrationtest/r/globalindex/ddl.result @@ -16,12 +16,10 @@ Error 8264 (HY000): Global Index is needed for index 'a', since the unique index alter table t partition by hash(b) partitions 3 update indexes (a global); alter table t add index idxErr (b) global; Error 8200 (HY000): Unsupported Global IndexOption on non-unique index -alter table t add unique index idxErr (b) global; -Error 8200 (HY000): Unsupported Global IndexOption on index including all columns in the partitioning expression +alter table t add unique index idxOK (b) global; create index idxErr on t (b) global; Error 8200 (HY000): Unsupported Global IndexOption on non-unique index -create unique index idxErr on t (b) global; -Error 8200 (HY000): Unsupported Global IndexOption on index including all columns in the partitioning expression +create unique index idxOK2 on t (b) global; alter table t remove partitioning; alter table t add index idxErr (b) global; Error 8200 (HY000): Unsupported Global Index on non-partitioned table @@ -70,13 +68,11 @@ alter table t partition by hash(b) partitions 3 UPDATE INDEXES (a GLOBAL); alter table t add index idxErr (b) global; Error 8200 (HY000): Unsupported Global IndexOption on non-unique index alter table t add unique index idxOK (a) global; -alter table t add unique index idxErr (b) global; -Error 8200 (HY000): Unsupported Global IndexOption on index including all columns in the partitioning expression +alter table t add unique index idxOK2 (b) global; create index idxErr on t (b) global; Error 8200 (HY000): Unsupported Global IndexOption on non-unique index -create unique index idxOK2 on t (a) global; -create unique index idxErr on t (b) global; -Error 8200 (HY000): Unsupported Global IndexOption on index including all columns in the partitioning expression +create unique index idxOK3 on t (a) global; +create unique index idxOK4 on t (b) global; drop table t; create table t(a int, b int, primary key (a) nonclustered global); Error 8200 (HY000): Unsupported Global Index on non-partitioned table diff --git a/tests/integrationtest/r/globalindex/insert.result b/tests/integrationtest/r/globalindex/insert.result index ab1d95f28c570..74e53a66c2f7e 100644 --- a/tests/integrationtest/r/globalindex/insert.result +++ b/tests/integrationtest/r/globalindex/insert.result @@ -4,3 +4,9 @@ insert into t values (1, 1), (1, 2) on duplicate key update a=1, b=3; select * from t use index (idx); a b 1 3 +alter table t add unique index idx1(b) global; +insert into t values (2, 4), (3, 4) on duplicate key update a=2, b=5; +select * from t use index (idx1); +a b +2 5 +1 3 diff --git a/tests/integrationtest/r/globalindex/mem_index_lookup.result b/tests/integrationtest/r/globalindex/mem_index_lookup.result index 1e7064d222b83..d337855387103 100644 --- a/tests/integrationtest/r/globalindex/mem_index_lookup.result +++ b/tests/integrationtest/r/globalindex/mem_index_lookup.result @@ -3,6 +3,7 @@ drop table if exists t; CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, +UNIQUE KEY `idx` (`a`) GLOBAL, UNIQUE KEY `idx1` (`b`) GLOBAL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin PARTITION BY HASH (`a`) PARTITIONS 5; @@ -34,12 +35,12 @@ a b 5 1 explain select * from t partition(p1) use index(idx1) where b <= 2 and a = 10; id estRows task access object operator info -Projection_5 3.32 root globalindex__mem_index_lookup.t.a, globalindex__mem_index_lookup.t.b -└─UnionScan_6 3.32 root eq(globalindex__mem_index_lookup.t.a, 10), le(globalindex__mem_index_lookup.t.b, 2) - └─IndexLookUp_12 3.32 root partition:dual +Projection_5 0.33 root globalindex__mem_index_lookup.t.a, globalindex__mem_index_lookup.t.b +└─UnionScan_6 0.33 root eq(globalindex__mem_index_lookup.t.a, 10), le(globalindex__mem_index_lookup.t.b, 2) + └─IndexLookUp_12 0.33 root partition:dual ├─Selection_10(Build) 3323.33 cop[tikv] in(globalindex__mem_index_lookup.t._tidb_tid, dual) │ └─IndexRangeScan_7 3323.33 cop[tikv] table:t, index:idx1(b) range:[-inf,2], keep order:false, stats:pseudo - └─Selection_11(Probe) 3.32 cop[tikv] eq(globalindex__mem_index_lookup.t.a, 10) + └─Selection_11(Probe) 0.33 cop[tikv] eq(globalindex__mem_index_lookup.t.a, 10) └─TableRowIDScan_8 3323.33 cop[tikv] table:t keep order:false, stats:pseudo select * from t partition(p1) use index(idx1) where b <= 2 and a = 10; a b @@ -55,6 +56,39 @@ select * from t partition(p0, p1) use index(idx1) where b <= 2; a b 1 2 5 1 +explain select * from t use index(idx) where a > 2; +id estRows task access object operator info +Projection_5 3333.33 root globalindex__mem_index_lookup.t.a, globalindex__mem_index_lookup.t.b +└─UnionScan_6 3333.33 root gt(globalindex__mem_index_lookup.t.a, 2) + └─IndexLookUp_10 3333.33 root partition:all + ├─IndexRangeScan_7(Build) 3333.33 cop[tikv] table:t, index:idx(a) range:(2,+inf], keep order:false, stats:pseudo + └─TableRowIDScan_8(Probe) 3333.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index(idx) where a > 2; +a b +3 4 +4 5 +5 1 +explain select * from t partition(p0) use index(idx) where a <= 2; +id estRows task access object operator info +Projection_5 3323.33 root NULL globalindex__mem_index_lookup.t.a, globalindex__mem_index_lookup.t.b +└─UnionScan_6 3323.33 root NULL le(globalindex__mem_index_lookup.t.a, 2) + └─IndexLookUp_11 3323.33 root partition:p0 NULL + ├─Selection_10(Build) 3323.33 cop[tikv] NULL in(globalindex__mem_index_lookup.t._tidb_tid, tid0) + │ └─IndexRangeScan_7 3323.33 cop[tikv] table:t, index:idx(a) range:[-inf,2], keep order:false, stats:pseudo + └─TableRowIDScan_8(Probe) 3323.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t partition(p0) use index(idx) where a <= 2; +a b +explain select * from t partition(p0, p1) use index(idx) where a <= 2; +id estRows task access object operator info +Projection_5 3323.33 root NULL globalindex__mem_index_lookup.t.a, globalindex__mem_index_lookup.t.b +└─UnionScan_6 3323.33 root NULL le(globalindex__mem_index_lookup.t.a, 2) + └─IndexLookUp_11 3323.33 root partition:p0,p1 NULL + ├─Selection_10(Build) 3323.33 cop[tikv] NULL in(globalindex__mem_index_lookup.t._tidb_tid, tid0, tid1) + │ └─IndexRangeScan_7 3323.33 cop[tikv] table:t, index:idx(a) range:[-inf,2], keep order:false, stats:pseudo + └─TableRowIDScan_8(Probe) 3323.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t partition(p0, p1) use index(idx) where a <= 2; +a b +1 2 rollback; # CommonHandle drop table if exists t; @@ -113,4 +147,38 @@ select * from t partition(p0, p1) use index(idx1) where b <= 2; a b c 2001 2 NULL 2005 1 NULL +explain select * from t use index(idx) where a > 2002; +id estRows task access object operator info +Projection_5 3333.33 root globalindex__mem_index_lookup.t.a, globalindex__mem_index_lookup.t.b, globalindex__mem_index_lookup.t.c +└─UnionScan_6 3333.33 root gt(globalindex__mem_index_lookup.t.a, 2002) + └─IndexLookUp_11 3333.33 root partition:all + ├─Selection_10(Build) 3333.33 cop[tikv] gt(globalindex__mem_index_lookup.t.a, 2002) + │ └─IndexFullScan_7 10000.00 cop[tikv] table:t, index:idx1(b) keep order:false, stats:pseudo + └─TableRowIDScan_8(Probe) 3333.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index(idx) where a > 2002; +a b c +2003 4 NULL +2004 5 NULL +2005 1 NULL +explain select * from t partition(p0) use index(idx) where a <= 2002; +id estRows task access object operator info +Projection_5 3323.33 root NULL globalindex__mem_index_lookup.t.a, globalindex__mem_index_lookup.t.b, globalindex__mem_index_lookup.t.c +└─UnionScan_6 3323.33 root NULL le(globalindex__mem_index_lookup.t.a, 2002) + └─IndexLookUp_11 3323.33 root partition:p0 NULL + ├─Selection_10(Build) 3323.33 cop[tikv] NULL in(globalindex__mem_index_lookup.t._tidb_tid, tid0), le(globalindex__mem_index_lookup.t.a, 2002) + │ └─IndexFullScan_7 10000.00 cop[tikv] table:t, index:idx1(b) keep order:false, stats:pseudo + └─TableRowIDScan_8(Probe) 3323.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t partition(p0) use index(idx) where a <= 2002; +a b c +explain select * from t partition(p0, p1) use index(idx) where a <= 2002; +id estRows task access object operator info +Projection_5 3323.33 root NULL globalindex__mem_index_lookup.t.a, globalindex__mem_index_lookup.t.b, globalindex__mem_index_lookup.t.c +└─UnionScan_6 3323.33 root NULL le(globalindex__mem_index_lookup.t.a, 2002) + └─IndexLookUp_11 3323.33 root partition:p0,p1 NULL + ├─Selection_10(Build) 3323.33 cop[tikv] NULL in(globalindex__mem_index_lookup.t._tidb_tid, tid0, tid1), le(globalindex__mem_index_lookup.t.a, 2002) + │ └─IndexFullScan_7 10000.00 cop[tikv] table:t, index:idx1(b) keep order:false, stats:pseudo + └─TableRowIDScan_8(Probe) 3323.33 cop[tikv] table:t keep order:false, stats:pseudo +select * from t partition(p0, p1) use index(idx) where a <= 2002; +a b c +2001 2 NULL rollback; diff --git a/tests/integrationtest/r/globalindex/mem_index_merge.result b/tests/integrationtest/r/globalindex/mem_index_merge.result index c066686bdc83c..0f2db4c3424c6 100644 --- a/tests/integrationtest/r/globalindex/mem_index_merge.result +++ b/tests/integrationtest/r/globalindex/mem_index_merge.result @@ -213,7 +213,8 @@ CREATE TABLE `tpk2` ( `c` int(11) NOT NULL, `d` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`b`), -UNIQUE KEY `uidx_a` (`a`) GLOBAL +UNIQUE KEY `uidx_a`(`a`) GLOBAL, +UNIQUE KEY `uidx_b`(`b`) GLOBAL ) PARTITION BY HASH (`b`) PARTITIONS 5; insert into tpk2 values (1, 2, 1, 1), (3, 6, 3, 3); begin; @@ -234,4 +235,20 @@ a b c d select /*+ use_index_merge(tpk2, uidx_a, primary) */ * from tpk2 where a=2 or b=4; a b c d 2 4 2 2 +## for two global indexes +explain select /*+ use_index_merge(tpk2, uidx_a, uidx_b) */ * from tpk2 where a=1 or b=4; +id estRows task access object operator info +Projection_5 2.00 root globalindex__mem_index_merge.tpk2.a, globalindex__mem_index_merge.tpk2.b, globalindex__mem_index_merge.tpk2.c, globalindex__mem_index_merge.tpk2.d +└─UnionScan_6 2.00 root or(eq(globalindex__mem_index_merge.tpk2.a, 1), eq(globalindex__mem_index_merge.tpk2.b, 4)) + └─IndexMerge_12 2.00 root partition:all type: union + ├─IndexRangeScan_7(Build) 1.00 cop[tikv] table:tpk2, index:uidx_a(a) range:[1,1], keep order:false, stats:pseudo + ├─IndexRangeScan_9(Build) 1.00 cop[tikv] table:tpk2, index:uidx_b(b) range:[4,4], keep order:false, stats:pseudo + └─TableRowIDScan_11(Probe) 2.00 cop[tikv] table:tpk2 keep order:false, stats:pseudo +select /*+ use_index_merge(tpk2, uidx_a, uidx_b) */ * from tpk2 where a=1 or b=4; +a b c d +1 2 1 1 +2 4 2 2 +select /*+ use_index_merge(tpk2, uidx_a, uidx_b) */ * from tpk2 where a=2 or b=4; +a b c d +2 4 2 2 rollback; diff --git a/tests/integrationtest/r/globalindex/mem_index_reader.result b/tests/integrationtest/r/globalindex/mem_index_reader.result index b64a93e5e197e..8fbe7b9f2050f 100644 --- a/tests/integrationtest/r/globalindex/mem_index_reader.result +++ b/tests/integrationtest/r/globalindex/mem_index_reader.result @@ -3,6 +3,7 @@ drop table if exists t; CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, +UNIQUE KEY `idx` (`a`) GLOBAL, UNIQUE KEY `idx1` (`b`) GLOBAL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin PARTITION BY HASH (`a`) PARTITIONS 5; @@ -41,12 +42,43 @@ select b from t partition(p0, p1) use index(idx1) where b <= 2; b 1 2 +explain select a from t use index(idx) where a > 2; +id estRows task access object operator info +Projection_5 3333.33 root globalindex__mem_index_reader.t.a +└─UnionScan_6 3333.33 root gt(globalindex__mem_index_reader.t.a, 2) + └─IndexReader_9 3333.33 root partition:all index:IndexRangeScan_7 + └─IndexRangeScan_7 3333.33 cop[tikv] table:t, index:idx(a) range:(2,+inf], keep order:false, stats:pseudo +select a from t use index(idx) where a > 2; +a +3 +4 +5 +explain select a from t partition(p0) use index(idx) where a <= 2; +id estRows task access object operator info +Projection_5 3323.33 root NULL globalindex__mem_index_reader.t.a +└─UnionScan_6 3323.33 root NULL le(globalindex__mem_index_reader.t.a, 2) + └─IndexReader_10 3323.33 root partition:p0 index:Selection_9 + └─Selection_9 3323.33 cop[tikv] NULL in(globalindex__mem_index_reader.t._tidb_tid, tid0) + └─IndexRangeScan_7 3323.33 cop[tikv] table:t, index:idx(a) range:[-inf,2], keep order:false, stats:pseudo +select a from t partition(p0) use index(idx) where a <= 2; +a +explain select a from t partition(p0, p1) use index(idx) where a <= 2; +id estRows task access object operator info +Projection_5 3323.33 root NULL globalindex__mem_index_reader.t.a +└─UnionScan_6 3323.33 root NULL le(globalindex__mem_index_reader.t.a, 2) + └─IndexReader_10 3323.33 root partition:p0,p1 index:Selection_9 + └─Selection_9 3323.33 cop[tikv] NULL in(globalindex__mem_index_reader.t._tidb_tid, tid0, tid1) + └─IndexRangeScan_7 3323.33 cop[tikv] table:t, index:idx(a) range:[-inf,2], keep order:false, stats:pseudo +select a from t partition(p0, p1) use index(idx) where a <= 2; +a +1 rollback; # CommonHandle drop table if exists t; CREATE TABLE `t` ( `a` year(4) primary key CLUSTERED, `b` int(11) DEFAULT NULL, +UNIQUE KEY `idx` (`a`) GLOBAL, UNIQUE KEY `idx1` (`b`) GLOBAL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin PARTITION BY HASH (`a`) PARTITIONS 5; @@ -85,4 +117,34 @@ select b from t partition(p0, p1) use index(idx1) where b <= 2; b 1 2 +explain select a from t use index(idx) where a > 2002; +id estRows task access object operator info +Projection_5 3333.33 root globalindex__mem_index_reader.t.a +└─UnionScan_6 3333.33 root gt(globalindex__mem_index_reader.t.a, 2002) + └─IndexReader_9 3333.33 root partition:all index:IndexRangeScan_7 + └─IndexRangeScan_7 3333.33 cop[tikv] table:t, index:idx(a) range:(2002,+inf], keep order:false, stats:pseudo +select a from t use index(idx) where a > 2002; +a +2003 +2004 +2005 +explain select a from t partition(p0) use index(idx) where a <= 2002; +id estRows task access object operator info +Projection_5 3323.33 root NULL globalindex__mem_index_reader.t.a +└─UnionScan_6 3323.33 root NULL le(globalindex__mem_index_reader.t.a, 2002) + └─IndexReader_10 3323.33 root partition:p0 index:Selection_9 + └─Selection_9 3323.33 cop[tikv] NULL in(globalindex__mem_index_reader.t._tidb_tid, tid0) + └─IndexRangeScan_7 3323.33 cop[tikv] table:t, index:idx(a) range:[-inf,2002], keep order:false, stats:pseudo +select a from t partition(p0) use index(idx) where a <= 2002; +a +explain select a from t partition(p0, p1) use index(idx) where a <= 2002; +id estRows task access object operator info +Projection_5 3323.33 root NULL globalindex__mem_index_reader.t.a +└─UnionScan_6 3323.33 root NULL le(globalindex__mem_index_reader.t.a, 2002) + └─IndexReader_10 3323.33 root partition:p0,p1 index:Selection_9 + └─Selection_9 3323.33 cop[tikv] NULL in(globalindex__mem_index_reader.t._tidb_tid, tid0, tid1) + └─IndexRangeScan_7 3323.33 cop[tikv] table:t, index:idx(a) range:[-inf,2002], keep order:false, stats:pseudo +select a from t partition(p0, p1) use index(idx) where a <= 2002; +a +2001 rollback; diff --git a/tests/integrationtest/r/globalindex/point_get.result b/tests/integrationtest/r/globalindex/point_get.result index 531110f22245f..d4b41c6abab42 100644 --- a/tests/integrationtest/r/globalindex/point_get.result +++ b/tests/integrationtest/r/globalindex/point_get.result @@ -30,6 +30,35 @@ a b c d 1 1 1 0 2 2 2 0 3 3 3 0 +# Add a global index include all partition columns. +alter table pt add unique index idx(a) global; +# Test PointGet +explain select a from pt where a = 1; +id estRows task access object operator info +Point_Get_1 1.00 root table:pt, index:idx(a) +select a from pt where a = 1; +a +1 +explain select a from pt partition(p1) where a = 1; +id estRows task access object operator info +Point_Get_1 1.00 root table:pt, index:idx(a) +select a from pt partition(p1) where a = 1; +a +explain select a from pt partition(p0) where a = 1; +id estRows task access object operator info +Point_Get_1 1.00 root table:pt, index:idx(a) +select a from pt partition(p0) where a = 1; +a +1 +# Test BatchPointGet +explain select * from pt where a in (1,2,3); +id estRows task access object operator info +Batch_Point_Get_1 3.00 root table:pt, index:idx(a) keep order:false, desc:false +select * from pt where a in (1,2,3); +a b c d +1 1 1 0 +2 2 2 0 +3 3 3 0 drop table if exists pt; # Clustered index table create table pt (a int, b int, c int, d int default 0, primary key (a, b) clustered, unique key uidx(c) global) @@ -62,3 +91,32 @@ a b c d 1 1 1 0 2 2 2 0 3 3 3 0 +# Add a global index include all partition columns. +alter table pt add unique index idx(a) global; +# Test PointGet +explain select a from pt where a = 1; +id estRows task access object operator info +Point_Get_1 1.00 root table:pt, index:idx(a) +select a from pt where a = 1; +a +1 +explain select a from pt partition(p1) where a = 1; +id estRows task access object operator info +Point_Get_1 1.00 root table:pt, index:idx(a) +select a from pt partition(p1) where a = 1; +a +explain select a from pt partition(p0) where a = 1; +id estRows task access object operator info +Point_Get_1 1.00 root table:pt, index:idx(a) +select a from pt partition(p0) where a = 1; +a +1 +# Test BatchPointGet +explain select * from pt where a in (1,2,3); +id estRows task access object operator info +Batch_Point_Get_1 3.00 root table:pt, index:idx(a) keep order:false, desc:false +select * from pt where a in (1,2,3); +a b c d +1 1 1 0 +2 2 2 0 +3 3 3 0 diff --git a/tests/integrationtest/r/globalindex/update.result b/tests/integrationtest/r/globalindex/update.result index 785ab1fec2791..6a138c912af1c 100644 --- a/tests/integrationtest/r/globalindex/update.result +++ b/tests/integrationtest/r/globalindex/update.result @@ -13,7 +13,7 @@ insert into t values (2, 2, 3); Error 1062 (23000): Duplicate entry '2' for key 't.idx1' rollback; drop table if exists t; -create table t ( a int, b int, c int, unique key idx(b) global) +create table t ( a int, b int, c int, unique key idx(b) global, unique index idx1(a) global) partition by range( a ) ( partition p1 values less than (10), partition p2 values less than (20), @@ -23,6 +23,8 @@ begin; insert into t values (1, 1, 1), (8, 8, 8), (11, 11, 11), (12, 12, 12); update t set a = 2, b = 12 where a = 11; Error 1062 (23000): Duplicate entry '12' for key 't.idx' +update t set a = 8, b = 13 where a = 11; +Error 1062 (23000): Duplicate entry '8' for key 't.idx1' rollback; insert into t values (1, 1, 1), (8, 8, 8), (11, 11, 11), (12, 12, 12); update t set a = 2 where a = 11; @@ -39,6 +41,18 @@ a b c 2 11 11 8 8 8 13 12 12 +explain select * from t use index(idx1) order by a; +id estRows task access object operator info +Projection_16 10000.00 root globalindex__update.t.a, globalindex__update.t.b, globalindex__update.t.c +└─IndexLookUp_15 10000.00 root partition:all + ├─IndexFullScan_12(Build) 10000.00 cop[tikv] table:t, index:idx1(a) keep order:true, stats:pseudo + └─TableRowIDScan_13(Probe) 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +select * from t use index(idx1) order by a; +a b c +1 1 1 +2 11 11 +8 8 8 +13 12 12 drop table t; create table t(a varchar(70), b mediumint(9), unique index idx_a(a) global, unique index idx_b(b)) partition by key(b) partitions 5; insert into t values ('',826534 ); diff --git a/tests/integrationtest/t/globalindex/aggregate.test b/tests/integrationtest/t/globalindex/aggregate.test index 9f5ee7cdb4ed4..5772ea9c8baca 100644 --- a/tests/integrationtest/t/globalindex/aggregate.test +++ b/tests/integrationtest/t/globalindex/aggregate.test @@ -20,3 +20,13 @@ select avg(id), max(id), min(id) from p use index(idx) group by c; explain format='brief' select avg(id), max(id), min(id) from p partition(p0) use index(idx) group by c; select avg(id), max(id), min(id) from p partition(p0) use index(idx) group by c; + +alter table p add unique index idx1(c, id) global; + +explain format='brief' select count(*), max(id), min(id) from p use index(idx1); +select count(*), max(id), min(id) from p use index(idx1); + +explain format='brief' select avg(id), max(id), min(id) from p use index(idx1) group by c; +--sorted_result +select avg(id), max(id), min(id) from p use index(idx1) group by c; + diff --git a/tests/integrationtest/t/globalindex/ddl.test b/tests/integrationtest/t/globalindex/ddl.test index 33770841674d0..3fcbb99f503aa 100644 --- a/tests/integrationtest/t/globalindex/ddl.test +++ b/tests/integrationtest/t/globalindex/ddl.test @@ -16,12 +16,10 @@ alter table t partition by hash(b) partitions 3; alter table t partition by hash(b) partitions 3 update indexes (a global); -- error 8200 alter table t add index idxErr (b) global; --- error 8200 -alter table t add unique index idxErr (b) global; +alter table t add unique index idxOK (b) global; -- error 8200 create index idxErr on t (b) global; --- error 8200 -create unique index idxErr on t (b) global; +create unique index idxOK2 on t (b) global; alter table t remove partitioning; -- error 8200 alter table t add index idxErr (b) global; @@ -64,13 +62,11 @@ alter table t partition by hash(b) partitions 3 UPDATE INDEXES (a GLOBAL); -- error 8200 alter table t add index idxErr (b) global; alter table t add unique index idxOK (a) global; --- error 8200 -alter table t add unique index idxErr (b) global; +alter table t add unique index idxOK2 (b) global; -- error 8200 create index idxErr on t (b) global; -create unique index idxOK2 on t (a) global; --- error 8200 -create unique index idxErr on t (b) global; +create unique index idxOK3 on t (a) global; +create unique index idxOK4 on t (b) global; drop table t; --error 8200 diff --git a/tests/integrationtest/t/globalindex/insert.test b/tests/integrationtest/t/globalindex/insert.test index c9d7805a4ca69..e4251d662a822 100644 --- a/tests/integrationtest/t/globalindex/insert.test +++ b/tests/integrationtest/t/globalindex/insert.test @@ -2,3 +2,9 @@ drop table if exists t; create table t(a int, b int, unique index idx(a) global) partition by hash(b) partitions 5; insert into t values (1, 1), (1, 2) on duplicate key update a=1, b=3; select * from t use index (idx); + +alter table t add unique index idx1(b) global; +insert into t values (2, 4), (3, 4) on duplicate key update a=2, b=5; +select * from t use index (idx1); + + diff --git a/tests/integrationtest/t/globalindex/mem_index_lookup.test b/tests/integrationtest/t/globalindex/mem_index_lookup.test index 057130fdc52aa..5bdff32c616c8 100644 --- a/tests/integrationtest/t/globalindex/mem_index_lookup.test +++ b/tests/integrationtest/t/globalindex/mem_index_lookup.test @@ -3,6 +3,7 @@ drop table if exists t; CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, + UNIQUE KEY `idx` (`a`) GLOBAL, UNIQUE KEY `idx1` (`b`) GLOBAL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin PARTITION BY HASH (`a`) PARTITIONS 5; @@ -30,6 +31,20 @@ explain select * from t partition(p0, p1) use index(idx1) where b <= 2; --sorted_result select * from t partition(p0, p1) use index(idx1) where b <= 2; +explain select * from t use index(idx) where a > 2; +--sorted_result +select * from t use index(idx) where a > 2; + +--replace_regex /_tidb_tid, [0-9]+\)/_tidb_tid, tid0)/ +explain select * from t partition(p0) use index(idx) where a <= 2; +--sorted_result +select * from t partition(p0) use index(idx) where a <= 2; + +--replace_regex /_tidb_tid, [0-9]+, [0-9]+\)/_tidb_tid, tid0, tid1)/ +explain select * from t partition(p0, p1) use index(idx) where a <= 2; +--sorted_result +select * from t partition(p0, p1) use index(idx) where a <= 2; + rollback; --echo # CommonHandle @@ -65,5 +80,20 @@ explain select * from t partition(p0, p1) use index(idx1) where b <= 2; --sorted_result select * from t partition(p0, p1) use index(idx1) where b <= 2; +explain select * from t use index(idx) where a > 2002; +--sorted_result +select * from t use index(idx) where a > 2002; + +--replace_regex /_tidb_tid, [0-9]+\)/_tidb_tid, tid0)/ +explain select * from t partition(p0) use index(idx) where a <= 2002; +--sorted_result +select * from t partition(p0) use index(idx) where a <= 2002; + +--replace_regex /_tidb_tid, [0-9]+, [0-9]+\)/_tidb_tid, tid0, tid1)/ +explain select * from t partition(p0, p1) use index(idx) where a <= 2002; +--sorted_result +select * from t partition(p0, p1) use index(idx) where a <= 2002; + + rollback; diff --git a/tests/integrationtest/t/globalindex/mem_index_merge.test b/tests/integrationtest/t/globalindex/mem_index_merge.test index 447c74e1a418b..f761ad06d4de9 100644 --- a/tests/integrationtest/t/globalindex/mem_index_merge.test +++ b/tests/integrationtest/t/globalindex/mem_index_merge.test @@ -114,7 +114,8 @@ CREATE TABLE `tpk2` ( `c` int(11) NOT NULL, `d` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`b`), - UNIQUE KEY `uidx_a` (`a`) GLOBAL + UNIQUE KEY `uidx_a`(`a`) GLOBAL, + UNIQUE KEY `uidx_b`(`b`) GLOBAL ) PARTITION BY HASH (`b`) PARTITIONS 5; insert into tpk2 values (1, 2, 1, 1), (3, 6, 3, 3); @@ -129,5 +130,12 @@ select /*+ use_index_merge(tpk2, uidx_a, primary) */ * from tpk2 where a=1 or b= --sorted_result select /*+ use_index_merge(tpk2, uidx_a, primary) */ * from tpk2 where a=2 or b=4; +--echo ## for two global indexes +explain select /*+ use_index_merge(tpk2, uidx_a, uidx_b) */ * from tpk2 where a=1 or b=4; +--sorted_result +select /*+ use_index_merge(tpk2, uidx_a, uidx_b) */ * from tpk2 where a=1 or b=4; +--sorted_result +select /*+ use_index_merge(tpk2, uidx_a, uidx_b) */ * from tpk2 where a=2 or b=4; + rollback; diff --git a/tests/integrationtest/t/globalindex/mem_index_reader.test b/tests/integrationtest/t/globalindex/mem_index_reader.test index 61dd77d42549b..d40ebeddb4f79 100644 --- a/tests/integrationtest/t/globalindex/mem_index_reader.test +++ b/tests/integrationtest/t/globalindex/mem_index_reader.test @@ -3,6 +3,7 @@ drop table if exists t; CREATE TABLE `t` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, + UNIQUE KEY `idx` (`a`) GLOBAL, UNIQUE KEY `idx1` (`b`) GLOBAL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin PARTITION BY HASH (`a`) PARTITIONS 5; @@ -26,6 +27,20 @@ explain select b from t partition(p0, p1) use index(idx1) where b <= 2; --sorted_result select b from t partition(p0, p1) use index(idx1) where b <= 2; +explain select a from t use index(idx) where a > 2; +--sorted_result +select a from t use index(idx) where a > 2; + +--replace_regex /_tidb_tid, [0-9]+\)/_tidb_tid, tid0)/ +explain select a from t partition(p0) use index(idx) where a <= 2; +--sorted_result +select a from t partition(p0) use index(idx) where a <= 2; + +--replace_regex /_tidb_tid, [0-9]+, [0-9]+\)/_tidb_tid, tid0, tid1)/ +explain select a from t partition(p0, p1) use index(idx) where a <= 2; +--sorted_result +select a from t partition(p0, p1) use index(idx) where a <= 2; + rollback; --echo # CommonHandle @@ -33,6 +48,7 @@ drop table if exists t; CREATE TABLE `t` ( `a` year(4) primary key CLUSTERED, `b` int(11) DEFAULT NULL, + UNIQUE KEY `idx` (`a`) GLOBAL, UNIQUE KEY `idx1` (`b`) GLOBAL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin PARTITION BY HASH (`a`) PARTITIONS 5; @@ -56,6 +72,20 @@ explain select b from t partition(p0, p1) use index(idx1) where b <= 2; --sorted_result select b from t partition(p0, p1) use index(idx1) where b <= 2; +explain select a from t use index(idx) where a > 2002; +--sorted_result +select a from t use index(idx) where a > 2002; + +--replace_regex /_tidb_tid, [0-9]+\)/_tidb_tid, tid0)/ +explain select a from t partition(p0) use index(idx) where a <= 2002; +--sorted_result +select a from t partition(p0) use index(idx) where a <= 2002; + +--replace_regex /_tidb_tid, [0-9]+, [0-9]+\)/_tidb_tid, tid0, tid1)/ +explain select a from t partition(p0, p1) use index(idx) where a <= 2002; +--sorted_result +select a from t partition(p0, p1) use index(idx) where a <= 2002; + rollback; diff --git a/tests/integrationtest/t/globalindex/point_get.test b/tests/integrationtest/t/globalindex/point_get.test index 78b2d78f63f26..3d77797086c7f 100644 --- a/tests/integrationtest/t/globalindex/point_get.test +++ b/tests/integrationtest/t/globalindex/point_get.test @@ -24,6 +24,24 @@ explain select c from pt where c in (1,2,3); --sorted_result select * from pt where c in (1,2,3); +--echo # Add a global index include all partition columns. +alter table pt add unique index idx(a) global; + +--echo # Test PointGet +explain select a from pt where a = 1; +select a from pt where a = 1; + +explain select a from pt partition(p1) where a = 1; +select a from pt partition(p1) where a = 1; + +explain select a from pt partition(p0) where a = 1; +select a from pt partition(p0) where a = 1; + +--echo # Test BatchPointGet +explain select * from pt where a in (1,2,3); +--sorted_result +select * from pt where a in (1,2,3); + drop table if exists pt; --echo # Clustered index table create table pt (a int, b int, c int, d int default 0, primary key (a, b) clustered, unique key uidx(c) global) @@ -49,3 +67,21 @@ explain select c from pt where c in (1,2,3); --sorted_result select * from pt where c in (1,2,3); +--echo # Add a global index include all partition columns. +alter table pt add unique index idx(a) global; + +--echo # Test PointGet +explain select a from pt where a = 1; +select a from pt where a = 1; + +explain select a from pt partition(p1) where a = 1; +select a from pt partition(p1) where a = 1; + +explain select a from pt partition(p0) where a = 1; +select a from pt partition(p0) where a = 1; + +--echo # Test BatchPointGet +explain select * from pt where a in (1,2,3); +--sorted_result +select * from pt where a in (1,2,3); + diff --git a/tests/integrationtest/t/globalindex/update.test b/tests/integrationtest/t/globalindex/update.test index b357dc1be0885..e383f37f589d6 100644 --- a/tests/integrationtest/t/globalindex/update.test +++ b/tests/integrationtest/t/globalindex/update.test @@ -15,7 +15,7 @@ insert into t values (2, 2, 3); rollback; drop table if exists t; -create table t ( a int, b int, c int, unique key idx(b) global) +create table t ( a int, b int, c int, unique key idx(b) global, unique index idx1(a) global) partition by range( a ) ( partition p1 values less than (10), partition p2 values less than (20), @@ -25,6 +25,8 @@ begin; insert into t values (1, 1, 1), (8, 8, 8), (11, 11, 11), (12, 12, 12); --error 1062 update t set a = 2, b = 12 where a = 11; +--error 1062 +update t set a = 8, b = 13 where a = 11; rollback; insert into t values (1, 1, 1), (8, 8, 8), (11, 11, 11), (12, 12, 12); @@ -32,6 +34,8 @@ update t set a = 2 where a = 11; update t set a = 13 where a = 12; explain select * from t use index(idx) order by a; select * from t use index(idx) order by a; +explain select * from t use index(idx1) order by a; +select * from t use index(idx1) order by a; # https://github.com/pingcap/tidb/issues/53750 drop table t;