Skip to content

Commit

Permalink
key partition supports one column
Browse files Browse the repository at this point in the history
Signed-off-by: TonsnakeLin <[email protected]>
  • Loading branch information
TonsnakeLin committed Feb 7, 2023
1 parent d669c60 commit 62e8709
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 132 deletions.
38 changes: 30 additions & 8 deletions ddl/partition.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,11 +462,15 @@ func buildTablePartitionInfo(ctx sessionctx.Context, s *ast.PartitionOptions, tb
ctx.GetSessionVars().StmtCtx.AppendWarning(dbterror.ErrUnsupportedCreatePartition.GenWithStack(fmt.Sprintf("Unsupported partition type %v, treat as normal table", s.Tp)))
return nil
}

mask := uint64(1)
for mask < s.Num {
mask <<= 1
}
pi := &model.PartitionInfo{
Type: s.Tp,
Enable: enable,
Num: s.Num,
Type: s.Tp,
Enable: enable,
Num: s.Num,
HashMask: mask - 1,
}
tbInfo.Partition = pi
if s.Expr != nil {
Expand Down Expand Up @@ -2860,8 +2864,9 @@ func AppendPartitionInfo(partitionInfo *model.PartitionInfo, buf *bytes.Buffer,
// include the /*!50100 or /*!50500 comments for TiDB.
// This also solves the issue with comments within comments that would happen for
// PLACEMENT POLICY options.
if partitionInfo.Type == model.PartitionTypeHash {
defaultPartitionDefinitions := true
defaultPartitionDefinitions := true
if partitionInfo.Type == model.PartitionTypeHash ||
partitionInfo.Type == model.PartitionTypeKey {
for i, def := range partitionInfo.Definitions {
if def.Name.O != fmt.Sprintf("p%d", i) {
defaultPartitionDefinitions = false
Expand All @@ -2874,15 +2879,32 @@ func AppendPartitionInfo(partitionInfo *model.PartitionInfo, buf *bytes.Buffer,
}

if defaultPartitionDefinitions {
fmt.Fprintf(buf, "\nPARTITION BY HASH (%s) PARTITIONS %d", partitionInfo.Expr, partitionInfo.Num)
if partitionInfo.Type == model.PartitionTypeHash {
fmt.Fprintf(buf, "\nPARTITION BY HASH (%s) PARTITIONS %d", partitionInfo.Expr, partitionInfo.Num)
} else {
buf.WriteString("\nPARTITION BY KEY (")
for i, col := range partitionInfo.Columns {
buf.WriteString(stringutil.Escape(col.O, sqlMode))
if i < len(partitionInfo.Columns)-1 {
buf.WriteString(",")
}
}
buf.WriteString(")")
fmt.Fprintf(buf, " PARTITIONS %d", partitionInfo.Num)
}
return
}
}
// this if statement takes care of lists/range columns case
if len(partitionInfo.Columns) > 0 {
// partitionInfo.Type == model.PartitionTypeRange || partitionInfo.Type == model.PartitionTypeList
// || partitionInfo.Type == model.PartitionTypeKey
// Notice that MySQL uses two spaces between LIST and COLUMNS...
fmt.Fprintf(buf, "\nPARTITION BY %s COLUMNS(", partitionInfo.Type.String())
if partitionInfo.Type == model.PartitionTypeKey {
fmt.Fprintf(buf, "\nPARTITION BY %s (", partitionInfo.Type.String())
} else {
fmt.Fprintf(buf, "\nPARTITION BY %s COLUMNS(", partitionInfo.Type.String())
}
for i, col := range partitionInfo.Columns {
buf.WriteString(stringutil.Escape(col.O, sqlMode))
if i < len(partitionInfo.Columns)-1 {
Expand Down
18 changes: 13 additions & 5 deletions executor/batch_point_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func (e *BatchPointGetExec) initialize(ctx context.Context) error {
continue
}

physID, err := getPhysID(e.tblInfo, e.partExpr, idxVals[e.partPos].GetInt64())
physID, err := getPhysID(e.tblInfo, e.partExpr, idxVals[e.partPos], idxVals[e.partPos].GetInt64())
if err != nil {
continue
}
Expand Down Expand Up @@ -357,7 +357,9 @@ func (e *BatchPointGetExec) initialize(ctx context.Context) error {
tID = e.physIDs[i]
} else {
if handle.IsInt() {
tID, err = getPhysID(e.tblInfo, e.partExpr, handle.IntValue())
d := &types.Datum{}
d.SetInt64(handle.IntValue())
tID, err = getPhysID(e.tblInfo, e.partExpr, *d, handle.IntValue())
if err != nil {
continue
}
Expand All @@ -366,7 +368,7 @@ func (e *BatchPointGetExec) initialize(ctx context.Context) error {
if err1 != nil {
return err1
}
tID, err = getPhysID(e.tblInfo, e.partExpr, d.GetInt64())
tID, err = getPhysID(e.tblInfo, e.partExpr, d, d.GetInt64())
if err != nil {
continue
}
Expand Down Expand Up @@ -527,7 +529,7 @@ func (getter *PessimisticLockCacheGetter) Get(_ context.Context, key kv.Key) ([]
return nil, kv.ErrNotExist
}

func getPhysID(tblInfo *model.TableInfo, partitionExpr *tables.PartitionExpr, intVal int64) (int64, error) {
func getPhysID(tblInfo *model.TableInfo, partitionExpr *tables.PartitionExpr, d types.Datum, intVal int64) (int64, error) {
pi := tblInfo.GetPartitionInfo()
if pi == nil {
return tblInfo.ID, nil
Expand All @@ -545,7 +547,13 @@ func getPhysID(tblInfo *model.TableInfo, partitionExpr *tables.PartitionExpr, in
if len(pi.Columns) > 1 {
return 0, errors.Errorf("unsupported partition type in BatchGet")
}
partIdx := mathutil.Abs(intVal % int64(pi.Num))
col := &expression.Column{}
*col = *partitionExpr.Cols[0]
col.Index = 0
partIdx, err := partitionExpr.LocateKeyPartition(nil, pi, []*expression.Column{col}, []types.Datum{d}, int64(pi.Num))
if err != nil {
return 0, errors.Errorf("unsupported partition type in BatchGet")
}
return pi.Definitions[partIdx].ID, nil
case model.PartitionTypeRange:
// we've check the type assertions in func TryFastPlan
Expand Down
1 change: 1 addition & 0 deletions parser/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,7 @@ type PartitionInfo struct {
DroppingDefinitions []PartitionDefinition `json:"dropping_definitions"`
States []PartitionState `json:"states"`
Num uint64 `json:"num"`
HashMask uint64 `json:"hash_mask"`
}

// Clone clones itself.
Expand Down
4 changes: 2 additions & 2 deletions planner/core/find_best_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,7 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
}
}
}
var hashPartColName *ast.ColumnName
var hashPartColName *model.CIStr
if tblInfo := ds.table.Meta(); canConvertPointGet && tblInfo.GetPartitionInfo() != nil {
// We do not build [batch] point get for dynamic table partitions now. This can be optimized.
if ds.ctx.GetSessionVars().StmtCtx.UseDynamicPartitionPrune() {
Expand Down Expand Up @@ -2207,7 +2207,7 @@ func (ds *DataSource) convertToPointGet(prop *property.PhysicalProperty, candida
}

func (ds *DataSource) convertToBatchPointGet(prop *property.PhysicalProperty,
candidate *candidatePath, hashPartColName *ast.ColumnName, opt *physicalOptimizeOp) (task task) {
candidate *candidatePath, hashPartColName *model.CIStr, opt *physicalOptimizeOp) (task task) {
if !prop.IsSortItemEmpty() && !candidate.isMatchProp {
return invalidTask
}
Expand Down
17 changes: 11 additions & 6 deletions planner/core/point_get_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -1778,7 +1778,11 @@ func getPartitionInfo(ctx sessionctx.Context, tbl *model.TableInfo, pairs []name
if len(pi.Columns) == 1 {
for i, pair := range pairs {
if pi.Columns[0].L == pair.colName {
pos, err := partitionExpr.LocateKeyPartition(ctx, pi, []types.Datum{pair.value}, int64(pi.Num))
col := &expression.Column{}
*col = *partitionExpr.ForKeyPruning.Cols[0]
col.Index = 0
pos, err := partitionExpr.LocateKeyPartition(ctx, pi, []*expression.Column{col},
[]types.Datum{pair.value}, int64(pi.Num))
if err != nil {
return nil, 0, 0, false
}
Expand Down Expand Up @@ -1893,12 +1897,12 @@ func getPartitionColumnPos(idx *model.IndexInfo, partitionExpr *tables.Partition
}

// getHashPartitionColumnPos gets the hash partition column's position in the unique index.
func getHashPartitionColumnPos(idx *model.IndexInfo, partitionColName *ast.ColumnName) int {
func getHashPartitionColumnPos(idx *model.IndexInfo, partitionColName *model.CIStr) int {
if partitionColName == nil {
return 0
}
for i, idxCol := range idx.Columns {
if partitionColName.Name.L == idxCol.Name.L {
if partitionColName.L == idxCol.Name.L {
return i
}
}
Expand Down Expand Up @@ -1926,7 +1930,7 @@ func getPartitionExpr(ctx sessionctx.Context, tbl *model.TableInfo) *tables.Part
return partitionExpr
}

func getHashOrKeyPartitionColumnName(ctx sessionctx.Context, tbl *model.TableInfo) *ast.ColumnName {
func getHashOrKeyPartitionColumnName(ctx sessionctx.Context, tbl *model.TableInfo) *model.CIStr {
pi := tbl.GetPartitionInfo()
if pi == nil {
return nil
Expand All @@ -1948,15 +1952,16 @@ func getHashOrKeyPartitionColumnName(ctx sessionctx.Context, tbl *model.TableInf
if len(pi.Columns) != 1 {
return nil
}

// used to judge wthether the key partition contains only one field
return &ast.ColumnName{}
return &pi.Columns[0]
}
expr := partitionExpr.OrigExpr
col, ok := expr.(*ast.ColumnNameExpr)
if !ok {
return nil
}
return col.Name
return &col.Name.Name
}

func findColNameByColID(cols []*model.ColumnInfo, col *expression.Column) *model.ColumnInfo {
Expand Down
115 changes: 25 additions & 90 deletions planner/core/rule_partition_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,109 +252,44 @@ func (s *partitionProcessor) findUsedKeyPartitions(ctx sessionctx.Context, tbl t
if err != nil {
return nil, nil, err
}
schema := expression.NewSchema(columns...)
partCols := make([]*expression.Column, len(partExpr.ColumnOffset))
colLen := make([]int, 0, len(partExpr.ColumnOffset))
for i, offset := range partExpr.ColumnOffset {
partCols[i] = schema.Columns[offset]
partCols[i].Index = i
colLen = append(colLen, partCols[i].RetType.GetFlen())
}

partCols, colLen := partExpr.GetPartColumns(columns)
detachedResult, err := ranger.DetachCondAndBuildRangeForPartition(ctx, conds, partCols, colLen, ctx.GetSessionVars().RangeMaxSize)
if err != nil {
return nil, nil, err
}
ranges := detachedResult.Ranges
used := make([]int, 0, len(ranges))
for _, r := range ranges {
if r.IsPointNullable(ctx) {
if !r.HighVal[0].IsNull() {
if len(r.HighVal) != len(partCols) {
used = []int{-1}
break
}
}
highLowVals := make([]types.Datum, 0, len(r.HighVal)+len(r.LowVal))
highLowVals = append(highLowVals, r.HighVal...)
highLowVals = append(highLowVals, r.LowVal...)
idx, err := partExpr.LocateKeyPartition(ctx, pi, highLowVals, int64(pi.Num))
if err != nil {
// If we failed to get the point position, we can just skip and ignore it.
continue
}

if len(partitionNames) > 0 && !s.findByName(partitionNames, pi.Definitions[idx].Name.L) {
continue
}
used = append(used, int(idx))
} else {
// processing hash partition pruning. eg:
// create table t2 (a int, b bigint, index (a), index (b)) partition by hash(a) partitions 10;
// desc select * from t2 where t2.a between 10 and 15;
// determine whether the partition key is int
/*
if col, ok := pe.(*expression.Column); ok && col.RetType.EvalType() == types.ETInt {
numPartitions := len(pi.Definitions)
posHigh, highIsNull, err := pe.EvalInt(ctx, chunk.MutRowFromDatums(r.HighVal).ToRow())
if err != nil {
return nil, nil, err
}
posLow, lowIsNull, err := pe.EvalInt(ctx, chunk.MutRowFromDatums(r.LowVal).ToRow())
if err != nil {
return nil, nil, err
}
// consider whether the range is closed or open
if r.LowExclude {
posLow++
}
if r.HighExclude {
posHigh--
}
var rangeScalar float64
if mysql.HasUnsignedFlag(col.RetType.GetFlag()) {
rangeScalar = float64(uint64(posHigh)) - float64(uint64(posLow)) // use float64 to avoid integer overflow
} else {
rangeScalar = float64(posHigh) - float64(posLow) // use float64 to avoid integer overflow
}
// if range is less than the number of partitions, there will be unused partitions we can prune out.
if rangeScalar < float64(numPartitions) && !highIsNull && !lowIsNull {
for i := posLow; i <= posHigh; i++ {
idx := mathutil.Abs(i % int64(pi.Num))
if len(partitionNames) > 0 && !s.findByName(partitionNames, pi.Definitions[idx].Name.L) {
continue
}
used = append(used, int(idx))
}
continue
}
// issue:#22619
if col.RetType.GetType() == mysql.TypeBit {
// maximum number of partitions is 8192
if col.RetType.GetFlen() > 0 && col.RetType.GetFlen() < int(gomath.Log2(mysql.PartitionCountLimit)) {
// all possible hash values
maxUsedPartitions := 1 << col.RetType.GetFlen()
if maxUsedPartitions < numPartitions {
for i := 0; i < maxUsedPartitions; i++ {
used = append(used, i)
}
continue
}
}
if len(partExpr.ForKeyPruning.Cols) > 1 {
used = []int{FullRange}
} else {
for _, r := range ranges {
if r.IsPointNullable(ctx) {
if !r.HighVal[0].IsNull() {
if len(r.HighVal) != len(partCols) {
used = []int{-1}
break
}
}
highLowVals := make([]types.Datum, 0, len(r.HighVal)+len(r.LowVal))
highLowVals = append(highLowVals, r.HighVal...)
highLowVals = append(highLowVals, r.LowVal...)
idx, err := partExpr.LocateKeyPartition(ctx, pi, partCols, highLowVals, int64(pi.Num))
if err != nil {
// If we failed to get the point position, we can just skip and ignore it.
continue
}

if len(partitionNames) > 0 && !s.findByName(partitionNames, pi.Definitions[idx].Name.L) {
continue
}
used = append(used, int(idx))
} else {
used = []int{FullRange}
break
*/
}
}
}

if len(partitionNames) > 0 && len(used) == 1 && used[0] == FullRange {
or := partitionRangeOR{partitionRange{0, len(pi.Definitions)}}
return s.convertToIntSlice(or, pi, partitionNames), nil, nil
Expand Down
Loading

0 comments on commit 62e8709

Please sign in to comment.