diff --git a/common/config.go b/common/config.go index 973ab54e752213f9a4055137906918b34e51040f..8240249d834202f94bc4ef5d74e4be3894e0e771 100644 --- a/common/config.go +++ b/common/config.go @@ -121,7 +121,7 @@ type Configuration struct { ExplainWarnAccessType []string `yaml:"explain-warn-access-type"` // 哪些 access type 不建议使用 ExplainMaxKeyLength int `yaml:"explain-max-keys"` // 最大 key_len ExplainMinPossibleKeys int `yaml:"explain-min-keys"` // 最小 possible_keys 警告 - ExplainMaxRows int `yaml:"explain-max-rows"` // 最大扫描行数警告 + ExplainMaxRows int64 `yaml:"explain-max-rows"` // 最大扫描行数警告 ExplainWarnExtra []string `yaml:"explain-warn-extra"` // 哪些 extra 信息会给警告 ExplainMaxFiltered float64 `yaml:"explain-max-filtered"` // filtered 大于该配置给出警告 ExplainWarnScalability []string `yaml:"explain-warn-scalability"` // 复杂度警告名单 @@ -641,7 +641,7 @@ func readCmdFlags() error { explainWarnAccessType := flag.String("explain-warn-access-type", strings.Join(Config.ExplainWarnAccessType, ","), "ExplainWarnAccessType, 哪些access type不建议使用") explainMaxKeyLength := flag.Int("explain-max-keys", Config.ExplainMaxKeyLength, "ExplainMaxKeyLength, 最大key_len") explainMinPossibleKeys := flag.Int("explain-min-keys", Config.ExplainMinPossibleKeys, "ExplainMinPossibleKeys, 最小possible_keys警告") - explainMaxRows := flag.Int("explain-max-rows", Config.ExplainMaxRows, "ExplainMaxRows, 最大扫描行数警告") + explainMaxRows := flag.Int64("explain-max-rows", Config.ExplainMaxRows, "ExplainMaxRows, 最大扫描行数警告") explainWarnExtra := flag.String("explain-warn-extra", strings.Join(Config.ExplainWarnExtra, ","), "ExplainWarnExtra, 哪些extra信息会给警告") explainMaxFiltered := flag.Float64("explain-max-filtered", Config.ExplainMaxFiltered, "ExplainMaxFiltered, filtered大于该配置给出警告") explainWarnScalability := flag.String("explain-warn-scalability", strings.Join(Config.ExplainWarnScalability, ","), "ExplainWarnScalability, 复杂度警告名单, 支持O(n),O(log n),O(1),O(?)") diff --git a/common/example_test.go b/common/example_test.go index 0aa3e00661b7f15124070524fff4d326e08ff44a..099b294d4d0082670230a8f3d390a0a0fae0ce9e 100644 --- a/common/example_test.go +++ b/common/example_test.go @@ -42,13 +42,16 @@ func ExampleIsColsPart() { b := []*Column{{Name: "1"}, {Name: "2"}} c := []*Column{{Name: "1"}, {Name: "3"}} d := []*Column{{Name: "1"}, {Name: "2"}, {Name: "3"}, {Name: "4"}} + id := []*Column{{Name: "id"}} + iD := []*Column{{Name: "iD"}} ab := IsColsPart(a, b) ac := IsColsPart(a, c) ad := IsColsPart(a, d) + idiD := IsColsPart(id, iD) // 大小写对比 - fmt.Println(ab, ac, ad) - // Output: true false true + fmt.Println(ab, ac, ad, idiD) + // Output: true false true true Log.Debug("Exiting function: %s", GetFunctionName()) } diff --git a/common/meta.go b/common/meta.go index c92b01b0d9767a83f9d6f632316302ff39c8171a..5ef117bd1f15ae36795b062fe360534a6e212528 100644 --- a/common/meta.go +++ b/common/meta.go @@ -93,7 +93,9 @@ func IsColsPart(a, b []*Column) bool { } for i := 0; i < times; i++ { - if a[i].DB != b[i].DB || a[i].Table != b[i].Table || a[i].Name != b[i].Name { + if strings.ToLower(a[i].DB) != strings.ToLower(b[i].DB) || + strings.ToLower(a[i].Table) != strings.ToLower(b[i].Table) || + strings.ToLower(a[i].Name) != strings.ToLower(b[i].Name) { return false } } diff --git a/database/explain.go b/database/explain.go index df00651655fba57ea6f2b00ab585f1f51cd5a55e..b06587a1c15774733b8caa266ab0c9d32bf9e56d 100644 --- a/database/explain.go +++ b/database/explain.go @@ -84,7 +84,7 @@ type ExplainRow struct { Key string KeyLen string // 索引长度,如果发生了index_merge, KeyLen 格式为 N,N,所以不能定义为整型 Ref []string - Rows int + Rows int64 Filtered float64 // 5.6 JSON, 5.7+, 5.5 EXTENDED Scalability string // O(1), O(n), O(log n), O(log n)+ Extra string @@ -131,7 +131,7 @@ type ExplainJSONTable struct { UsedKeyParts []string `json:"used_key_parts"` KeyLength string `json:"key_length"` Ref []string `json:"ref"` - RowsExaminedPerScan int `json:"rows_examined_per_scan"` + RowsExaminedPerScan int64 `json:"rows_examined_per_scan"` RowsProducedPerJoin int `json:"rows_produced_per_join"` Filtered string `json:"filtered"` UsingIndex bool `json:"using_index"` @@ -318,6 +318,7 @@ var ExplainAccessType = map[string]string{ // ExplainScalability ACCESS TYPE对应的运算复杂度 [AccessType]scalability map var ExplainScalability = map[string]string{ + "NULL": "NULL", "ALL": "O(n)", "index": "O(n)", "range": "O(log n)+", @@ -784,7 +785,7 @@ func parseTraditionalExplainText(content string) (explainRows []ExplainRow, err colsMap := make(map[string]string) for _, l := range lines[3:] { var keylen string - var rows int + var rows int64 var filtered float64 var partitions string // 跳过分割线 @@ -816,7 +817,7 @@ func parseTraditionalExplainText(content string) (explainRows []ExplainRow, err keylen = colsMap["key_len"] - rows, err = strconv.Atoi(colsMap["Rows"]) + rows, err = strconv.ParseInt(colsMap["Rows"], 10, 64) if err != nil { rows = 0 } @@ -908,7 +909,7 @@ func parseVerticalExplainText(content string) (explainRows []ExplainRow, err err } if strings.HasPrefix(l, "Rows:") { rows := strings.TrimPrefix(l, "Rows: ") - explainRow.Rows, err = strconv.Atoi(rows) + explainRow.Rows, err = strconv.ParseInt(rows, 10, 64) if err != nil { explainRow.Rows = 0 } @@ -957,15 +958,21 @@ func ParseExplainResult(res QueryResult, formatType int) (exp *ExplainInfo, err } /* - +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ - | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | - +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ - | 1 | SIMPLE | film | NULL | ALL | NULL | NULL | NULL | NULL | 1000 | 100.00 | NULL | - +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ + +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ + | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ + | 1 | SIMPLE | film | NULL | ALL | NULL | NULL | NULL | NULL | 1000 | 100.00 | NULL | + +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+ + + +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------+ + | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------+ + | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | no matching row in const table | + +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------+ */ // Different MySQL version has different columns define - var selectType, table, partitions, accessType, possibleKeys, key, keyLen, ref, extra []byte + var selectType, table, partitions, accessType, possibleKeys, key, keyLen, ref, extra, rows, filtered []byte expRow := ExplainRow{} explainFields := make([]interface{}, 0) fields := map[string]interface{}{ @@ -978,8 +985,8 @@ func ParseExplainResult(res QueryResult, formatType int) (exp *ExplainInfo, err "key": &key, "key_len": &keyLen, "ref": &ref, - "rows": &expRow.Rows, - "filtered": &expRow.Filtered, + "rows": &rows, + "filtered": &filtered, "Extra": &extra, } cols, err := res.Rows.Columns() @@ -1009,6 +1016,8 @@ func ParseExplainResult(res QueryResult, formatType int) (exp *ExplainInfo, err expRow.Key = NullString(key) expRow.KeyLen = NullString(keyLen) expRow.Ref = strings.Split(NullString(ref), ",") + expRow.Rows = NullInt(rows) + expRow.Filtered = NullFloat(filtered) expRow.Extra = NullString(extra) // MySQL bug: https://bugs.mysql.com/bug.php?id=34124 @@ -1115,7 +1124,9 @@ func PrintMarkdownExplainTable(exp *ExplainInfo) string { } scalability := row.Scalability for _, s := range common.Config.ExplainWarnScalability { - scalability = "☠️ **" + s + "**" + if s == scalability { + scalability = "☠️ **" + s + "**" + } } buf = append(buf, fmt.Sprintln("|", row.ID, " |", common.MarkdownEscape(row.SelectType), diff --git a/database/mysql.go b/database/mysql.go index 520c532cdd7badf71f007438b134afa332129cea..76239f3252685cf74c3d4684db7264aca2d739e3 100644 --- a/database/mysql.go +++ b/database/mysql.go @@ -319,6 +319,24 @@ func NullString(buf []byte) string { return string(buf) } +// NullFloat null able float +func NullFloat(buf []byte) float64 { + if buf == nil { + return 0 + } + f, _ := strconv.ParseFloat(string(buf), 64) + return f +} + +// NullInt null able int +func NullInt(buf []byte) int64 { + if buf == nil { + return 0 + } + i, _ := strconv.ParseInt(string(buf), 10, 64) + return i +} + // quoteEscape sql_mode=no_backslash_escapes func quoteEscape(source string) string { var buf bytes.Buffer