-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
planner: move index advisor into the kernel (#55820)
ref #12303
- Loading branch information
Showing
11 changed files
with
1,699 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") | ||
|
||
go_library( | ||
name = "indexadvisor", | ||
srcs = [ | ||
"model.go", | ||
"optimizer.go", | ||
"utils.go", | ||
], | ||
importpath = "github.com/pingcap/tidb/pkg/planner/indexadvisor", | ||
visibility = ["//visibility:public"], | ||
deps = [ | ||
"//pkg/domain", | ||
"//pkg/infoschema", | ||
"//pkg/meta/model", | ||
"//pkg/parser", | ||
"//pkg/parser/ast", | ||
"//pkg/parser/model", | ||
"//pkg/parser/mysql", | ||
"//pkg/parser/opcode", | ||
"//pkg/planner/util/fixcontrol", | ||
"//pkg/sessionctx", | ||
"//pkg/types", | ||
"//pkg/types/parser_driver", | ||
"//pkg/util/logutil", | ||
"//pkg/util/parser", | ||
"//pkg/util/set", | ||
"@org_uber_go_zap//:zap", | ||
], | ||
) | ||
|
||
go_test( | ||
name = "indexadvisor_test", | ||
timeout = "short", | ||
srcs = [ | ||
"optimizer_test.go", | ||
"utils_test.go", | ||
], | ||
flaky = True, | ||
shard_count = 17, | ||
deps = [ | ||
":indexadvisor", | ||
"//pkg/parser/mysql", | ||
"//pkg/testkit", | ||
"//pkg/util/set", | ||
"@com_github_stretchr_testify//require", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
// Copyright 2024 PingCAP, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package indexadvisor | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
"strings" | ||
) | ||
|
||
// Query represents a Query statement. | ||
type Query struct { // DQL or DML | ||
Alias string | ||
SchemaName string | ||
Text string | ||
Frequency int | ||
CostPerMon float64 | ||
} | ||
|
||
// Key returns the key of the Query. | ||
func (q Query) Key() string { | ||
return q.Text | ||
} | ||
|
||
// Column represents a column. | ||
type Column struct { | ||
SchemaName string | ||
TableName string | ||
ColumnName string | ||
} | ||
|
||
// NewColumn creates a new column. | ||
func NewColumn(schemaName, tableName, columnName string) Column { | ||
return Column{SchemaName: strings.ToLower(schemaName), | ||
TableName: strings.ToLower(tableName), ColumnName: strings.ToLower(columnName)} | ||
} | ||
|
||
// NewColumns creates new columns. | ||
func NewColumns(schemaName, tableName string, columnNames ...string) []Column { | ||
cols := make([]Column, 0, len(columnNames)) | ||
for _, col := range columnNames { | ||
cols = append(cols, NewColumn(schemaName, tableName, col)) | ||
} | ||
return cols | ||
} | ||
|
||
// Key returns the key of the column. | ||
func (c Column) Key() string { | ||
return fmt.Sprintf("%v.%v.%v", c.SchemaName, c.TableName, c.ColumnName) | ||
} | ||
|
||
// Index represents an index. | ||
type Index struct { | ||
SchemaName string | ||
TableName string | ||
IndexName string | ||
Columns []Column | ||
} | ||
|
||
// NewIndex creates a new index. | ||
func NewIndex(schemaName, tableName, indexName string, columns ...string) Index { | ||
return Index{SchemaName: strings.ToLower(schemaName), TableName: strings.ToLower(tableName), | ||
IndexName: strings.ToLower(indexName), Columns: NewColumns(schemaName, tableName, columns...)} | ||
} | ||
|
||
// NewIndexWithColumns creates a new index with columns. | ||
func NewIndexWithColumns(indexName string, columns ...Column) Index { | ||
names := make([]string, len(columns)) | ||
for i, col := range columns { | ||
names[i] = col.ColumnName | ||
} | ||
return NewIndex(columns[0].SchemaName, columns[0].TableName, indexName, names...) | ||
} | ||
|
||
// Key returns the key of the index. | ||
func (i Index) Key() string { | ||
names := make([]string, 0, len(i.Columns)) | ||
for _, col := range i.Columns { | ||
names = append(names, col.ColumnName) | ||
} | ||
return fmt.Sprintf("%v.%v(%v)", i.SchemaName, i.TableName, strings.Join(names, ",")) | ||
} | ||
|
||
// PrefixContain returns whether j is a prefix of i. | ||
func (i Index) PrefixContain(j Index) bool { | ||
if i.SchemaName != j.SchemaName || i.TableName != j.TableName || len(i.Columns) < len(j.Columns) { | ||
return false | ||
} | ||
for k := range j.Columns { | ||
if i.Columns[k].ColumnName != j.Columns[k].ColumnName { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// IndexSetCost is the cost of a index configuration. | ||
type IndexSetCost struct { | ||
TotalWorkloadQueryCost float64 | ||
TotalNumberOfIndexColumns int | ||
IndexKeysStr string // IndexKeysStr is the string representation of the index keys. | ||
} | ||
|
||
// Less returns whether the cost of c is less than the cost of other. | ||
func (c IndexSetCost) Less(other IndexSetCost) bool { | ||
if c.TotalWorkloadQueryCost == 0 { // not initialized | ||
return false | ||
} | ||
if other.TotalWorkloadQueryCost == 0 { // not initialized | ||
return true | ||
} | ||
cc, cOther := c.TotalWorkloadQueryCost, other.TotalWorkloadQueryCost | ||
if math.Abs(cc-cOther) > 10 && math.Abs(cc-cOther)/math.Max(cc, cOther) > 0.001 { | ||
// their cost is very different, then the less cost, the better. | ||
return cc < cOther | ||
} | ||
|
||
if c.TotalNumberOfIndexColumns != other.TotalNumberOfIndexColumns { | ||
// if they have the same cost, then the less columns, the better. | ||
return c.TotalNumberOfIndexColumns < other.TotalNumberOfIndexColumns | ||
} | ||
|
||
// to make the result stable. | ||
return c.IndexKeysStr < other.IndexKeysStr | ||
} |
Oops, something went wrong.