Skip to content

Commit

Permalink
Merge branch 'master' into move_ddl_test_2
Browse files Browse the repository at this point in the history
  • Loading branch information
hawkingrei authored Jan 29, 2023
2 parents 859dcc5 + 90c5a87 commit e7028b6
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 59 deletions.
7 changes: 0 additions & 7 deletions ddl/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ package ddl
import (
"context"
"encoding/json"
"flag"
"fmt"
"runtime"
"strconv"
Expand Down Expand Up @@ -1249,12 +1248,6 @@ var (
RunInGoTest bool
)

func init() {
if flag.Lookup("test.v") != nil || flag.Lookup("check.v") != nil {
RunInGoTest = true
}
}

// GetDropOrTruncateTableInfoFromJobsByStore implements GetDropOrTruncateTableInfoFromJobs
func GetDropOrTruncateTableInfoFromJobsByStore(jobs []*model.Job, gcSafePoint uint64, getTable func(uint64, int64, int64) (*model.TableInfo, error), fn func(*model.Job, *model.TableInfo) (bool, error)) (bool, error) {
for _, job := range jobs {
Expand Down
3 changes: 3 additions & 0 deletions planner/core/find_best_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,9 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
if canConvertPointGet && expression.MaybeOverOptimized4PlanCache(ds.ctx, path.AccessConds) {
canConvertPointGet = ds.canConvertToPointGetForPlanCache(path)
}
if canConvertPointGet && path.Index != nil && path.Index.MVIndex {
canConvertPointGet = false // cannot use PointGet upon MVIndex
}

if canConvertPointGet && !path.IsIntHandlePath {
// We simply do not build [batch] point get for prefix indexes. This can be optimized.
Expand Down
105 changes: 55 additions & 50 deletions planner/core/indexmerge_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package core

import (
"fmt"
"math"
"strings"

Expand All @@ -37,6 +36,16 @@ import (

// generateIndexMergePath generates IndexMerge AccessPaths on this DataSource.
func (ds *DataSource) generateIndexMergePath() error {
var warningMsg string
stmtCtx := ds.ctx.GetSessionVars().StmtCtx
defer func() {
if len(ds.indexMergeHints) > 0 && warningMsg != "" {
ds.indexMergeHints = nil
stmtCtx.AppendWarning(errors.Errorf(warningMsg))
logutil.BgLogger().Debug(warningMsg)
}
}()

// Consider the IndexMergePath. Now, we just generate `IndexMergePath` in DNF case.
// Use allConds instread of pushedDownConds,
// because we want to use IndexMerge even if some expr cannot be pushed to TiKV.
Expand All @@ -46,11 +55,26 @@ func (ds *DataSource) generateIndexMergePath() error {
indexMergeConds = append(indexMergeConds, expression.PushDownNot(ds.ctx, expr))
}

stmtCtx := ds.ctx.GetSessionVars().StmtCtx
isPossibleIdxMerge := len(indexMergeConds) > 0 && // have corresponding access conditions, and
(len(ds.possibleAccessPaths) > 1 || // (have multiple index paths, or
(len(ds.possibleAccessPaths) == 1 && isMVIndexPath(ds.possibleAccessPaths[0]))) // have a MVIndex)

if !isPossibleIdxMerge {
warningMsg = "IndexMerge is inapplicable or disabled. No available filter or available index."
return nil
}

sessionAndStmtPermission := (ds.ctx.GetSessionVars().GetEnableIndexMerge() || len(ds.indexMergeHints) > 0) && !stmtCtx.NoIndexMergeHint
if !sessionAndStmtPermission {
warningMsg = "IndexMerge is inapplicable or disabled. Got no_index_merge hint or tidb_enable_index_merge is off."
return nil
}

if ds.tableInfo.TempTableType == model.TempTableLocal {
warningMsg = "IndexMerge is inapplicable or disabled. Cannot use IndexMerge on temporary table."
return nil
}

// We current do not consider `IndexMergePath`:
// 1. If there is an index path.
// 2. TODO: If there exists exprs that cannot be pushed down. This is to avoid wrongly estRow of Selection added by rule_predicate_push_down.
Expand Down Expand Up @@ -87,26 +111,37 @@ func (ds *DataSource) generateIndexMergePath() error {
}
}

if isPossibleIdxMerge && sessionAndStmtPermission && needConsiderIndexMerge && ds.tableInfo.TempTableType != model.TempTableLocal {
err := ds.generateAndPruneIndexMergePath(indexMergeConds, ds.indexMergeHints != nil)
if err != nil {
return err
}
} else if len(ds.indexMergeHints) > 0 {
if !needConsiderIndexMerge {
warningMsg = "IndexMerge is inapplicable or disabled. "
return nil
}
regularPathCount := len(ds.possibleAccessPaths)
if err := ds.generateAndPruneIndexMergePath(indexMergeConds); err != nil {
return err
}

// If without hints, it means that `enableIndexMerge` is true
if len(ds.indexMergeHints) == 0 {
return nil
}
// If len(indexMergeHints) > 0, then add warnings if index-merge hints cannot work.
if regularPathCount == len(ds.possibleAccessPaths) {
ds.indexMergeHints = nil
var msg string
if !isPossibleIdxMerge {
msg = "No available filter or available index."
} else if !sessionAndStmtPermission {
msg = "Got no_index_merge hint or tidb_enable_index_merge is off."
} else if ds.tableInfo.TempTableType == model.TempTableLocal {
msg = "Cannot use IndexMerge on temporary table."
}
msg = fmt.Sprintf("IndexMerge is inapplicable or disabled. %s", msg)
stmtCtx.AppendWarning(errors.Errorf(msg))
logutil.BgLogger().Debug(msg)
ds.ctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("IndexMerge is inapplicable"))
return nil
}

// If len(indexMergeHints) > 0 and some index-merge paths were added, then prune all other non-index-merge paths.
ds.possibleAccessPaths = ds.possibleAccessPaths[regularPathCount:]
minRowCount := ds.possibleAccessPaths[0].CountAfterAccess
for _, path := range ds.possibleAccessPaths {
if minRowCount < path.CountAfterAccess {
minRowCount = path.CountAfterAccess
}
}
if ds.stats.RowCount > minRowCount {
ds.stats = ds.tableStats.ScaleByExpectCnt(minRowCount)
}
return nil
}

Expand Down Expand Up @@ -441,7 +476,7 @@ func (ds *DataSource) generateIndexMergeAndPaths(normalPathCnt int) *util.Access
return indexMergePath
}

func (ds *DataSource) generateAndPruneIndexMergePath(indexMergeConds []expression.Expression, needPrune bool) error {
func (ds *DataSource) generateAndPruneIndexMergePath(indexMergeConds []expression.Expression) error {
regularPathCount := len(ds.possibleAccessPaths)
// 1. Generate possible IndexMerge paths for `OR`.
err := ds.generateIndexMergeOrPaths(indexMergeConds)
Expand All @@ -461,36 +496,6 @@ func (ds *DataSource) generateAndPruneIndexMergePath(indexMergeConds []expressio
if mvIndexMergePath != nil {
ds.possibleAccessPaths = append(ds.possibleAccessPaths, mvIndexMergePath...)
}

// 4. If needed, append a warning if no IndexMerge is generated.

// If without hints, it means that `enableIndexMerge` is true
if len(ds.indexMergeHints) == 0 {
return nil
}
// With hints and without generated IndexMerge paths
if regularPathCount == len(ds.possibleAccessPaths) {
ds.indexMergeHints = nil
ds.ctx.GetSessionVars().StmtCtx.AppendWarning(errors.Errorf("IndexMerge is inapplicable"))
return nil
}

// 4. If needPrune is true, prune non-IndexMerge paths.

// Do not need to consider the regular paths in find_best_task().
// So we can use index merge's row count as DataSource's row count.
if needPrune {
ds.possibleAccessPaths = ds.possibleAccessPaths[regularPathCount:]
minRowCount := ds.possibleAccessPaths[0].CountAfterAccess
for _, path := range ds.possibleAccessPaths {
if minRowCount < path.CountAfterAccess {
minRowCount = path.CountAfterAccess
}
}
if ds.stats.RowCount > minRowCount {
ds.stats = ds.tableStats.ScaleByExpectCnt(minRowCount)
}
}
return nil
}

Expand Down
24 changes: 24 additions & 0 deletions planner/core/indexmerge_path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
package core_test

import (
"strings"
"testing"

"github.com/pingcap/tidb/planner/core"
"github.com/pingcap/tidb/testkit"
"github.com/pingcap/tidb/testkit/testdata"
"github.com/stretchr/testify/require"
)

func TestIndexMergeJSONMemberOf(t *testing.T) {
Expand Down Expand Up @@ -149,3 +151,25 @@ func TestMVIndexIndexMergePlanCache(t *testing.T) {
tk.MustExec("execute st")
tk.MustQuery("select @@last_plan_from_cache").Check(testkit.Rows("0"))
}

func TestMVIndexPointGet(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec(`create table t(j json, unique kj((cast(j as signed array))))`)

for _, sql := range []string{
"select j from t where j=1",
"select j from t where j=1 or j=2",
"select j from t where j in (1, 2)",
} {
plan := tk.MustQuery("explain " + sql).Rows()
hasPointGet := false
for _, line := range plan {
if strings.Contains(strings.ToLower(line[0].(string)), "point") {
hasPointGet = true
}
}
require.True(t, !hasPointGet) // no point-get plan
}
}
4 changes: 2 additions & 2 deletions planner/core/point_get_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ func newBatchPointGetPlan(
}
}
for _, idxInfo := range tbl.Indices {
if !idxInfo.Unique || idxInfo.State != model.StatePublic || idxInfo.Invisible ||
if !idxInfo.Unique || idxInfo.State != model.StatePublic || idxInfo.Invisible || idxInfo.MVIndex ||
!indexIsAvailableByHints(idxInfo, indexHints) {
continue
}
Expand Down Expand Up @@ -1099,7 +1099,7 @@ func tryPointGetPlan(ctx sessionctx.Context, selStmt *ast.SelectStmt, check bool
var err error

for _, idxInfo := range tbl.Indices {
if !idxInfo.Unique || idxInfo.State != model.StatePublic || idxInfo.Invisible ||
if !idxInfo.Unique || idxInfo.State != model.StatePublic || idxInfo.Invisible || idxInfo.MVIndex ||
!indexIsAvailableByHints(idxInfo, tblName.IndexHints) {
continue
}
Expand Down

0 comments on commit e7028b6

Please sign in to comment.