Skip to content

Commit

Permalink
ddl: Allow global Index including all columns in the partitioning exp…
Browse files Browse the repository at this point in the history
…ression (#56868)

close #56230
  • Loading branch information
Defined2014 authored Oct 30, 2024
1 parent aa83395 commit fc116a7
Show file tree
Hide file tree
Showing 17 changed files with 417 additions and 77 deletions.
79 changes: 28 additions & 51 deletions pkg/ddl/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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()
Expand Down
22 changes: 22 additions & 0 deletions tests/integrationtest/r/globalindex/aggregate.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
14 changes: 5 additions & 9 deletions tests/integrationtest/r/globalindex/ddl.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions tests/integrationtest/r/globalindex/insert.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
76 changes: 72 additions & 4 deletions tests/integrationtest/r/globalindex/mem_index_lookup.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
19 changes: 18 additions & 1 deletion tests/integrationtest/r/globalindex/mem_index_merge.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Loading

0 comments on commit fc116a7

Please # to comment.