Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ddl: Allow global Index including all columns in the partitioning expression #56868

Merged
merged 9 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
mjonss marked this conversation as resolved.
Show resolved Hide resolved
├─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