diff --git a/planner/core/common_plans.go b/planner/core/common_plans.go index 9190d5a9997ed..78c97f9e83974 100644 --- a/planner/core/common_plans.go +++ b/planner/core/common_plans.go @@ -1315,49 +1315,3 @@ func IsPointUpdateByAutoCommit(ctx sessionctx.Context, p Plan) (bool, error) { } return false, nil } - -func buildSchemaAndNameFromIndex(cols []*expression.Column, dbName model.CIStr, tblInfo *model.TableInfo, idxInfo *model.IndexInfo) (*expression.Schema, types.NameSlice) { - schema := expression.NewSchema(cols...) - idxCols := idxInfo.Columns - names := make([]*types.FieldName, 0, len(idxCols)) - tblName := tblInfo.Name - for _, col := range idxCols { - names = append(names, &types.FieldName{ - OrigTblName: tblName, - OrigColName: col.Name, - DBName: dbName, - TblName: tblName, - ColName: col.Name, - }) - } - return schema, names -} - -func buildSchemaAndNameFromPKCol(pkCol *expression.Column, dbName model.CIStr, tblInfo *model.TableInfo) (*expression.Schema, types.NameSlice) { - schema := expression.NewSchema([]*expression.Column{pkCol}...) - names := make([]*types.FieldName, 0, 1) - tblName := tblInfo.Name - col := tblInfo.GetPkColInfo() - names = append(names, &types.FieldName{ - OrigTblName: tblName, - OrigColName: col.Name, - DBName: dbName, - TblName: tblName, - ColName: col.Name, - }) - return schema, names -} - -func locateHashPartition(ctx sessionctx.Context, expr expression.Expression, pi *model.PartitionInfo, r []types.Datum) (int, error) { - ret, isNull, err := expr.EvalInt(ctx, chunk.MutRowFromDatums(r).ToRow()) - if err != nil { - return 0, err - } - if isNull { - return 0, nil - } - if ret < 0 { - ret = 0 - ret - } - return int(ret % int64(pi.Num)), nil -} diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index e14dd2f2f4332..2fe45c983a19f 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -2607,6 +2607,22 @@ func (s *testIntegrationSuite) TestReorderSimplifiedOuterJoins(c *C) { } } +func (s *testIntegrationSuite) TestIndexMergeConstantTrue(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t;") + tk.MustExec("create table t(a int primary key, b int not null, key(b))") + tk.MustExec("delete /*+ use_index_merge(t) */ FROM t WHERE a=1 OR (b < SOME (SELECT /*+ use_index_merge(t)*/ b FROM t WHERE a<2 OR b<2))") + + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int not null, b int not null, key(a), key(b))") + tk.MustExec("delete /*+ use_index_merge(t) */ FROM t WHERE a=1 OR (b < SOME (SELECT /*+ use_index_merge(t)*/ b FROM t WHERE a<2 OR b<2))") + + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int primary key, b int not null, c int, key(a), key(b,c))") + tk.MustExec("delete /*+ use_index_merge(t) */ FROM t WHERE a=1 OR (a<2 and b<2)") +} + func (s *testIntegrationSerialSuite) TestPushDownAggForMPP(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index ddba36644b2ac..1e9c9ae48c081 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -1367,23 +1367,6 @@ func buildHandleCols(ctx sessionctx.Context, tbl *model.TableInfo, schema *expre return &IntHandleCols{col: handleCol} } -func findHandleCol(tbl *model.TableInfo, schema *expression.Schema) *expression.Column { - // fields len is 0 for update and delete. - var handleCol *expression.Column - if tbl.PKIsHandle { - for i, col := range tbl.Columns { - if mysql.HasPriKeyFlag(col.Flag) && tbl.PKIsHandle { - handleCol = schema.Columns[i] - } - } - } - if !tbl.IsCommonHandle && handleCol == nil { - handleCol = colInfoToColumn(model.NewExtraHandleColInfo(), schema.Len()) - schema.Append(handleCol) - } - return handleCol -} - func getPartitionInfo(ctx sessionctx.Context, tbl *model.TableInfo, pairs []nameValuePair) (*model.PartitionDefinition, int) { partitionColName := getHashPartitionColumnName(ctx, tbl) if partitionColName == nil { diff --git a/planner/core/stats.go b/planner/core/stats.go index c6c3e88442cd0..eeb5e86463536 100644 --- a/planner/core/stats.go +++ b/planner/core/stats.go @@ -506,8 +506,10 @@ func (ds *DataSource) accessPathsForConds(conditions []expression.Expression, us logutil.BgLogger().Debug("can not derive statistics of a path", zap.Error(err)) continue } - if len(path.AccessConds) == 0 { - // If AccessConds is empty, we ignore the access path. + // If `AccessConds` is empty, we ignore the access path. + // If the path contains a full range, ignore it also. This can happen when `AccessConds` is constant true, and + // it comes from the result of a subquery, so it is not folded. + if len(path.AccessConds) == 0 || ranger.HasFullRange(path.Ranges) { continue } // If we have point or empty range, just remove other possible paths. @@ -531,8 +533,10 @@ func (ds *DataSource) accessPathsForConds(conditions []expression.Expression, us continue } noIntervalRanges := ds.deriveIndexPathStats(path, conditions, true) - if len(path.AccessConds) == 0 { - // If AccessConds is empty, we ignore the access path. + // If `AccessConds` is empty, we ignore the access path. + // If the path contains a full range, ignore it also. This can happen when `AccessConds` is constant true, and + // it comes from the result of a subquery, so it is not folded. + if len(path.AccessConds) == 0 || ranger.HasFullRange(path.Ranges) { continue } // If we have empty range, or point range on unique index, just remove other possible paths. @@ -561,9 +565,9 @@ func (ds *DataSource) buildIndexMergePartialPath(indexAccessPaths []*util.Access minEstRowIndex := 0 minEstRow := math.MaxFloat64 for i := 0; i < len(indexAccessPaths); i++ { - rc, err := ds.stats.HistColl.GetRowCountByIndexRanges(ds.ctx.GetSessionVars().StmtCtx, indexAccessPaths[i].Index.ID, indexAccessPaths[i].Ranges) - if err != nil { - return nil, err + rc := indexAccessPaths[i].CountAfterAccess + if len(indexAccessPaths[i].IndexFilters) > 0 { + rc = indexAccessPaths[i].CountAfterIndex } if rc < minEstRow { minEstRowIndex = i diff --git a/util/localpool/localpool_test.go b/util/localpool/localpool_test.go index 6d9d49e81f958..77c4f92e80171 100644 --- a/util/localpool/localpool_test.go +++ b/util/localpool/localpool_test.go @@ -25,6 +25,7 @@ import ( ) type Obj struct { + // nolint:unused val int64 // nolint:structcheck // Dummy field to make it non-empty. } diff --git a/util/ranger/types.go b/util/ranger/types.go index 20f7a1509a1ce..26548ac1815bb 100644 --- a/util/ranger/types.go +++ b/util/ranger/types.go @@ -122,6 +122,16 @@ func (ran *Range) IsFullRange() bool { return true } +// HasFullRange checks if any range in the slice is a full range. +func HasFullRange(ranges []*Range) bool { + for _, ran := range ranges { + if ran.IsFullRange() { + return true + } + } + return false +} + // String implements the Stringer interface. func (ran *Range) String() string { lowStrs := make([]string, 0, len(ran.LowVal))