diff --git a/planner/core/logical_plans.go b/planner/core/logical_plans.go index 6ea6cc21f8395..411937b4a315f 100644 --- a/planner/core/logical_plans.go +++ b/planner/core/logical_plans.go @@ -372,6 +372,16 @@ type accessPath struct { forced bool } +// getTablePath finds the TablePath from a group of accessPaths. +func getTablePath(paths []*accessPath) *accessPath { + for _, path := range paths { + if path.isTablePath { + return path + } + } + return nil +} + // deriveTablePathStats will fulfill the information that the accessPath need. // And it will check whether the primary key is covered only by point query. func (ds *DataSource) deriveTablePathStats(path *accessPath) (bool, error) { diff --git a/planner/core/physical_plan_test.go b/planner/core/physical_plan_test.go index 91df45c2a73dc..e1f7e3bdf4f27 100644 --- a/planner/core/physical_plan_test.go +++ b/planner/core/physical_plan_test.go @@ -65,6 +65,10 @@ func (s *testPlanSuite) TestDAGPlanBuilderSimpleCase(c *C) { sql: "select * from t t1 use index(c_d_e)", best: "IndexLookUp(Index(t.c_d_e)[[NULL,+inf]], Table(t))", }, + { + sql: "select f from t use index() where f = 1", + best: "TableReader(Table(t)->Sel([eq(test.t.f, 1)]))", + }, // Test ts + Sort vs. DoubleRead + filter. { sql: "select a from t where a between 1 and 2 order by c", diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 86a6ffe381d71..d9c3e5fb9619f 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -478,6 +478,17 @@ func getPossibleAccessPaths(indexHints []*ast.IndexHint, tblInfo *model.TableInf } hasScanHint = true + + // It is syntactically valid to omit index_list for USE INDEX, which means “use no indexes”. + // Omitting index_list for FORCE INDEX or IGNORE INDEX is a syntax error. + // See https://dev.mysql.com/doc/refman/8.0/en/index-hints.html. + if hint.IndexNames == nil && hint.HintType != ast.HintIgnore { + if path := getTablePath(publicPaths); path != nil { + hasUseOrForce = true + path.forced = true + available = append(available, path) + } + } for _, idxName := range hint.IndexNames { path := getPathByIndexName(publicPaths, idxName, tblInfo) if path == nil {