diff --git a/advisor/heuristic.go b/advisor/heuristic.go index 3b571614d311cfe132b38dcfa50bca9e7869c2a7..acde83dfa4211e1be80f2210f57d7e686d20a85e 100644 --- a/advisor/heuristic.go +++ b/advisor/heuristic.go @@ -616,28 +616,6 @@ func (q *Query4Audit) RuleDiffGroupByOrderBy() Rule { return rule } -// RuleMixOrderBy CLA.007 -func (q *Query4Audit) RuleMixOrderBy() Rule { - var rule = q.RuleOK() - var direction string - err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { - switch n := node.(type) { - case sqlparser.OrderBy: - for _, order := range n { - // 比较相邻两个order by列的方向 - if direction != "" && order.Direction != direction { - rule = HeuristicRules["CLA.007"] - return false, nil - } - direction = order.Direction - } - } - return true, nil - }, q.Stmt) - common.LogIfError(err, "") - return rule -} - // RuleExplicitOrderBy CLA.008 func (q *Query4Audit) RuleExplicitOrderBy() Rule { var rule = q.RuleOK() diff --git a/advisor/heuristic_test.go b/advisor/heuristic_test.go index 013e4eb73f363ead8c6011447d3390295709ffac..ed4506049d011e0fe40565883031e728979d868c 100644 --- a/advisor/heuristic_test.go +++ b/advisor/heuristic_test.go @@ -340,26 +340,6 @@ func TestRuleDiffGroupByOrderBy(t *testing.T) { common.Log.Debug("Exiting function: %s", common.GetFunctionName()) } -// CLA.007 -func TestRuleMixOrderBy(t *testing.T) { - common.Log.Debug("Entering function: %s", common.GetFunctionName()) - sqls := []string{ - "select c1,c2,c3 from t1 where c1='foo' order by c2 desc, c3 asc", - } - for _, sql := range sqls { - q, err := NewQuery4Audit(sql) - if err == nil { - rule := q.RuleMixOrderBy() - if rule.Item != "CLA.007" { - t.Error("Rule not match:", rule.Item, "Expect : CLA.007") - } - } else { - t.Error("sqlparser.Parse Error:", err) - } - } - common.Log.Debug("Exiting function: %s", common.GetFunctionName()) -} - // CLA.008 func TestRuleExplicitOrderBy(t *testing.T) { common.Log.Debug("Entering function: %s", common.GetFunctionName()) @@ -3016,9 +2996,13 @@ func TestRuleOrderByMultiDirection(t *testing.T) { sqls := [][]string{ { `SELECT col FROM tbl order by col desc, col2 asc`, + `SELECT col FROM tbl order by col desc, col2`, + `SELECT col FROM tbl order by col, col2 desc`, }, { `SELECT col FROM tbl order by col, col2`, + `SELECT col FROM tbl order by col desc, col2 desc`, + `SELECT col FROM tbl order by col asc, col2 asc`, }, } for _, sql := range sqls[0] { diff --git a/advisor/rules.go b/advisor/rules.go index 67555d7d7637c74693c65e8f3b0ec48ec0164709..f5490065a10c31924b13273d7498314799ad450b 100644 --- a/advisor/rules.go +++ b/advisor/rules.go @@ -341,14 +341,6 @@ func InitHeuristicRules() { Case: "select tb1.col, tb2.col from tb1, tb2 where id=1 group by tb1.col, tb2.col", Func: (*Query4Audit).RuleDiffGroupByOrderBy, }, - "CLA.007": { - Item: "CLA.007", - Severity: "L2", - Summary: "ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引", - Content: `ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。`, - Case: "select c1,c2,c3 from t1 where c1='foo' order by c2 desc, c3 asc", - Func: (*Query4Audit).RuleMixOrderBy, - }, "CLA.008": { Item: "CLA.008", Severity: "L2", @@ -830,7 +822,7 @@ func InitHeuristicRules() { Item: "KEY.008", Severity: "L4", Summary: "ORDER BY 多个列但排序方向不同时可能无法使用索引", - Content: `在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。`, + Content: `在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。`, Case: "SELECT * FROM tbl ORDER BY a DESC, b ASC;", Func: (*Query4Audit).RuleOrderByMultiDirection, }, diff --git a/advisor/testdata/TestListHeuristicRules.golden b/advisor/testdata/TestListHeuristicRules.golden index a92be37d215e29ddbe4f4ac37b467c7f5b1e8414..c5ec8e79808401abc7e4b644327fedcb72f65700 100644 --- a/advisor/testdata/TestListHeuristicRules.golden +++ b/advisor/testdata/TestListHeuristicRules.golden @@ -272,16 +272,6 @@ select id from test where id=1 order by id ```sql select tb1.col, tb2.col from tb1, tb2 where id=1 group by tb1.col, tb2.col ``` -## ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引 - -* **Item**:CLA.007 -* **Severity**:L2 -* **Content**:ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。 -* **Case**: - -```sql -select c1,c2,c3 from t1 where c1='foo' order by c2 desc, c3 asc -``` ## 请为 GROUP BY 显示添加 ORDER BY 条件 * **Item**:CLA.008 @@ -846,7 +836,7 @@ CREATE TABLE tbl (a int); * **Item**:KEY.008 * **Severity**:L4 -* **Content**:在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 +* **Content**:在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 * **Case**: ```sql diff --git a/advisor/testdata/TestMergeConflictHeuristicRules.golden b/advisor/testdata/TestMergeConflictHeuristicRules.golden index cbfaba6d8cd1bab23f6cd1bae3514244b564f339..d1ae84bc8d34bffa150fdae78d128aa5ecf4561e 100644 --- a/advisor/testdata/TestMergeConflictHeuristicRules.golden +++ b/advisor/testdata/TestMergeConflictHeuristicRules.golden @@ -24,7 +24,6 @@ advisor.Rule{Item:"CLA.003", Severity:"L2", Summary:"不建议使用带 OFFSET advisor.Rule{Item:"CLA.004", Severity:"L2", Summary:"不建议对常量进行 GROUP BY", Content:"GROUP BY 1 表示按第一列进行 GROUP BY。如果在 GROUP BY 子句中使用数字,而不是表达式或列名称,当查询列顺序改变时,可能会导致问题。", Case:"select col1,col2 from tbl group by 1", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"CLA.005", Severity:"L2", Summary:"ORDER BY 常数列没有任何意义", Content:"SQL 逻辑上可能存在错误; 最多只是一个无用的操作,不会更改查询结果。", Case:"select id from test where id=1 order by id", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"CLA.006", Severity:"L4", Summary:"在不同的表中 GROUP BY 或 ORDER BY", Content:"这将强制使用临时表和 filesort,可能产生巨大性能隐患,并且可能消耗大量内存和磁盘上的临时空间。", Case:"select tb1.col, tb2.col from tb1, tb2 where id=1 group by tb1.col, tb2.col", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} -advisor.Rule{Item:"CLA.007", Severity:"L2", Summary:"ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引", Content:"ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。", Case:"select c1,c2,c3 from t1 where c1='foo' order by c2 desc, c3 asc", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"CLA.008", Severity:"L2", Summary:"请为 GROUP BY 显示添加 ORDER BY 条件", Content:"默认 MySQL 会对 'GROUP BY col1, col2, ...' 请求按如下顺序排序 'ORDER BY col1, col2, ...'。如果 GROUP BY 语句不指定 ORDER BY 条件会导致无谓的排序产生,如果不需要排序建议添加 'ORDER BY NULL'。", Case:"select c1,c2,c3 from t1 where c1='foo' group by c2", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"CLA.009", Severity:"L2", Summary:"ORDER BY 的条件为表达式", Content:"当 ORDER BY 条件为表达式或函数时会使用到临时表,如果在未指定 WHERE 或 WHERE 条件返回的结果集较大时性能会很差。", Case:"select description from film where title ='ACADEMY DINOSAUR' order by length-language_id;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"CLA.010", Severity:"L2", Summary:"GROUP BY 的条件为表达式", Content:"当 GROUP BY 条件为表达式或函数时会使用到临时表,如果在未指定 WHERE 或 WHERE 条件返回的结果集较大时性能会很差。", Case:"select description from film where title ='ACADEMY DINOSAUR' GROUP BY length-language_id;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} @@ -78,7 +77,7 @@ advisor.Rule{Item:"KEY.004", Severity:"L0", Summary:"提醒:请将索引属性 advisor.Rule{Item:"KEY.005", Severity:"L2", Summary:"表建的索引过多", Content:"表建的索引过多", Case:"CREATE TABLE tbl ( a int, b int, c int, KEY idx_a (`a`),KEY idx_b(`b`),KEY idx_c(`c`));", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"KEY.006", Severity:"L4", Summary:"主键中的列过多", Content:"主键中的列过多", Case:"CREATE TABLE tbl ( a int, b int, c int, PRIMARY KEY(`a`,`b`,`c`));", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"KEY.007", Severity:"L4", Summary:"未指定主键或主键非 int 或 bigint", Content:"未指定主键或主键非 int 或 bigint,建议将主键设置为 int unsigned 或 bigint unsigned。", Case:"CREATE TABLE tbl (a int);", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} -advisor.Rule{Item:"KEY.008", Severity:"L4", Summary:"ORDER BY 多个列但排序方向不同时可能无法使用索引", Content:"在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。", Case:"SELECT * FROM tbl ORDER BY a DESC, b ASC;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} +advisor.Rule{Item:"KEY.008", Severity:"L4", Summary:"ORDER BY 多个列但排序方向不同时可能无法使用索引", Content:"在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。", Case:"SELECT * FROM tbl ORDER BY a DESC, b ASC;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"KEY.009", Severity:"L0", Summary:"添加唯一索引前请注意检查数据唯一性", Content:"请提前检查添加唯一索引列的数据唯一性,如果数据不唯一在线表结构调整时将有可能自动将重复列删除,这有可能导致数据丢失。", Case:"CREATE UNIQUE INDEX part_of_name ON customer (name(10));", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"KEY.010", Severity:"L0", Summary:"全文索引不是银弹", Content:"全文索引主要用于解决模糊查询的性能问题,但需要控制好查询的频率和并发度。同时注意调整 ft_min_word_len, ft_max_word_len, ngram_token_size 等参数。", Case:"CREATE TABLE `tb` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `ip` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`), FULLTEXT KEY `ip` (`ip`) ) ENGINE=InnoDB;", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} advisor.Rule{Item:"KWR.001", Severity:"L2", Summary:"SQL_CALC_FOUND_ROWS 效率低下", Content:"因为 SQL_CALC_FOUND_ROWS 不能很好地扩展,所以可能导致性能问题; 建议业务使用其他策略来替代 SQL_CALC_FOUND_ROWS 提供的计数功能,比如:分页结果展示等。", Case:"select SQL_CALC_FOUND_ROWS col from tbl where id>1000", Position:0, Func:func(*advisor.Query4Audit) advisor.Rule {...}} diff --git a/database/testdata/TestFindColumn.golden b/database/testdata/TestFindColumn.golden index f6d064f49649ec85e88c680bd7c9bfc42ce85811..59cfca5138f442ee1f5e8762593e14be6cf9c08e 100644 --- a/database/testdata/TestFindColumn.golden +++ b/database/testdata/TestFindColumn.golden @@ -5,8 +5,8 @@ Table: "film", DB: "sakila", DataType: "smallint unsigned", - Character: "utf8", - Collation: "utf8_general_ci", + Character: "utf8mb3", + Collation: "utf8mb3_general_ci", Cardinality: 0, Null: "", Key: "", diff --git a/database/testdata/TestShowColumns.golden b/database/testdata/TestShowColumns.golden index c4e34b8925f3ad3dd095012ecc6af29a6c347533..44e29e20583f403bdb28bad15132ee51211b5a2f 100644 --- a/database/testdata/TestShowColumns.golden +++ b/database/testdata/TestShowColumns.golden @@ -15,7 +15,7 @@ { Field: "first_name", Type: "varchar(45)", - Collation: {0x75, 0x74, 0x66, 0x38, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x63, 0x69}, + Collation: {0x75, 0x74, 0x66, 0x38, 0x6d, 0x62, 0x33, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x63, 0x69}, Null: "NO", Key: "", Default: nil, @@ -26,7 +26,7 @@ { Field: "last_name", Type: "varchar(45)", - Collation: {0x75, 0x74, 0x66, 0x38, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x63, 0x69}, + Collation: {0x75, 0x74, 0x66, 0x38, 0x6d, 0x62, 0x33, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x63, 0x69}, Null: "NO", Key: "", Default: nil, @@ -37,7 +37,7 @@ { Field: "film_info", Type: "text", - Collation: {0x75, 0x74, 0x66, 0x38, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x63, 0x69}, + Collation: {0x75, 0x74, 0x66, 0x38, 0x6d, 0x62, 0x33, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x63, 0x69}, Null: "YES", Key: "", Default: nil, diff --git a/doc/heuristic.md b/doc/heuristic.md index a92be37d215e29ddbe4f4ac37b467c7f5b1e8414..c5ec8e79808401abc7e4b644327fedcb72f65700 100644 --- a/doc/heuristic.md +++ b/doc/heuristic.md @@ -272,16 +272,6 @@ select id from test where id=1 order by id ```sql select tb1.col, tb2.col from tb1, tb2 where id=1 group by tb1.col, tb2.col ``` -## ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引 - -* **Item**:CLA.007 -* **Severity**:L2 -* **Content**:ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。 -* **Case**: - -```sql -select c1,c2,c3 from t1 where c1='foo' order by c2 desc, c3 asc -``` ## 请为 GROUP BY 显示添加 ORDER BY 条件 * **Item**:CLA.008 @@ -846,7 +836,7 @@ CREATE TABLE tbl (a int); * **Item**:KEY.008 * **Severity**:L4 -* **Content**:在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 +* **Content**:在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 * **Case**: ```sql diff --git a/test/fixture/test_Check_soar_for_pipe_input.golden b/test/fixture/test_Check_soar_for_pipe_input.golden index 2c1f7dc137461b23b4ec5434127d42dea5696e2d..12c5a593e65e595d5f5968b7c55a07fef4e69acd 100644 --- a/test/fixture/test_Check_soar_for_pipe_input.golden +++ b/test/fixture/test_Check_soar_for_pipe_input.golden @@ -577,7 +577,7 @@ ORDER BY # Query: 6E9B96CA3F0E6BDA -★ ★ ★ ☆ ☆ 65分 +★ ★ ★ ☆ ☆ 75分 ```sql @@ -591,14 +591,6 @@ ORDER BY release_year ASC, language_id DESC ``` -## ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引 - -* **Item:** CLA.007 - -* **Severity:** L2 - -* **Content:** ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。 - ## 不建议使用 SELECT * 类型查询 * **Item:** COL.001 @@ -613,7 +605,7 @@ ORDER BY * **Severity:** L4 -* **Content:** 在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 +* **Content:** 在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 # Query: 2EAACFD7030EA528 @@ -2024,7 +2016,7 @@ FROM # Query: E48A20D0413512DA -★ ★ ☆ ☆ ☆ 50分 +★ ★ ★ ☆ ☆ 60分 ```sql @@ -2056,14 +2048,6 @@ ORDER BY * **Content:** 在列或表别名(如"tbl AS alias")中, 明确使用 AS 关键字比隐含别名(如"tbl alias")更易懂。 -## ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引 - -* **Item:** CLA.007 - -* **Severity:** L2 - -* **Content:** ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。 - ## 同一张表被连接两次 * **Item:** JOI.002 @@ -2329,7 +2313,7 @@ ORDER BY * **Severity:** L4 -* **Content:** 在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 +* **Content:** 在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 # Query: C11ECE7AE5F80CE5 diff --git a/test/fixture/test_Check_soar_query_for_input_file.golden b/test/fixture/test_Check_soar_query_for_input_file.golden index 2c1f7dc137461b23b4ec5434127d42dea5696e2d..12c5a593e65e595d5f5968b7c55a07fef4e69acd 100644 --- a/test/fixture/test_Check_soar_query_for_input_file.golden +++ b/test/fixture/test_Check_soar_query_for_input_file.golden @@ -577,7 +577,7 @@ ORDER BY # Query: 6E9B96CA3F0E6BDA -★ ★ ★ ☆ ☆ 65分 +★ ★ ★ ☆ ☆ 75分 ```sql @@ -591,14 +591,6 @@ ORDER BY release_year ASC, language_id DESC ``` -## ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引 - -* **Item:** CLA.007 - -* **Severity:** L2 - -* **Content:** ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。 - ## 不建议使用 SELECT * 类型查询 * **Item:** COL.001 @@ -613,7 +605,7 @@ ORDER BY * **Severity:** L4 -* **Content:** 在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 +* **Content:** 在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 # Query: 2EAACFD7030EA528 @@ -2024,7 +2016,7 @@ FROM # Query: E48A20D0413512DA -★ ★ ☆ ☆ ☆ 50分 +★ ★ ★ ☆ ☆ 60分 ```sql @@ -2056,14 +2048,6 @@ ORDER BY * **Content:** 在列或表别名(如"tbl AS alias")中, 明确使用 AS 关键字比隐含别名(如"tbl alias")更易懂。 -## ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引 - -* **Item:** CLA.007 - -* **Severity:** L2 - -* **Content:** ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。 - ## 同一张表被连接两次 * **Item:** JOI.002 @@ -2329,7 +2313,7 @@ ORDER BY * **Severity:** L4 -* **Content:** 在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 +* **Content:** 在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 # Query: C11ECE7AE5F80CE5 diff --git a/test/fixture/test_Run_all_test_cases.golden b/test/fixture/test_Run_all_test_cases.golden index 8cee1399dfde64a9819c4bb777a54584823c2cb2..173d337216f009b6a9a1c9eee48048c26f08b015 100644 --- a/test/fixture/test_Run_all_test_cases.golden +++ b/test/fixture/test_Run_all_test_cases.golden @@ -1233,7 +1233,7 @@ ORDER BY # Query: 6E9B96CA3F0E6BDA -★ ★ ☆ ☆ ☆ 55分 +★ ★ ★ ☆ ☆ 65分 ```sql @@ -1284,14 +1284,6 @@ ORDER BY -## ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引 - -* **Item:** CLA.007 - -* **Severity:** L2 - -* **Content:** ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。 - ## 不建议使用 SELECT * 类型查询 * **Item:** COL.001 @@ -1306,7 +1298,7 @@ ORDER BY * **Severity:** L4 -* **Content:** 在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 +* **Content:** 在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 # Query: 2EAACFD7030EA528 @@ -2463,7 +2455,7 @@ FROM | 1 | PRIMARY | *b* | NULL | eq\_ref | PRIMARY | PRIMARY | 2 | sakila.a.country\_id | 1 | ☠️ **100.00%** | O(log n) | NULL | | 2 | UNION | *b* | NULL | ALL | NULL | NULL | NULL | NULL | 109 | ☠️ **100.00%** | ☠️ **O(n)** | NULL | | 2 | UNION | *a* | NULL | ref | idx\_fk\_country\_id | idx\_fk\_country\_id | 2 | sakila.b.country\_id | 5 | ☠️ **100.00%** | O(log n) | NULL | -| 2 | UNION | *a* | NULL | ref | idx\_fk\_country\_id | idx\_fk\_country\_id | 2 | sakila.b.country\_id | 5 | ☠️ **100.00%** | O(log n) | NULL | +| 3 | UNION RESULT | ** | NULL | ALL | NULL | NULL | NULL | NULL | 0 | n% | ☠️ **O(n)** | Using temporary | @@ -2473,6 +2465,8 @@ FROM * **PRIMARY**: 最外层的select. +* **UNION RESULT**: UNION查询的结果集. + * **UNION**: UNION中的第二个或后面的SELECT查询, 不依赖于外部查询的结果集. #### Type信息解读 @@ -2483,6 +2477,10 @@ FROM * ☠️ **ALL**: 最坏的情况, 从头到尾全表扫描. +#### Extra信息解读 + +* ☠️ **Using temporary**: 表示MySQL在对查询结果排序时使用临时表. 常见于排序order by和分组查询group by. + ## 建议使用 AS 关键字显示声明一个别名 @@ -2539,7 +2537,7 @@ WHERE | 1 | PRIMARY | *a* | NULL | ref | idx\_fk\_country\_id | idx\_fk\_country\_id | 2 | sakila.b.country\_id | 5 | n% | O(log n) | Using where; Not exists | | 2 | UNION | *a* | NULL | ALL | NULL | NULL | NULL | NULL | 600 | ☠️ **100.00%** | ☠️ **O(n)** | NULL | | 2 | UNION | *b* | NULL | eq\_ref | PRIMARY | PRIMARY | 2 | sakila.a.country\_id | 1 | n% | O(log n) | Using where; Not exists | -| 2 | UNION | *b* | NULL | eq\_ref | PRIMARY | PRIMARY | 2 | sakila.a.country\_id | 1 | n% | O(log n) | Using where; Not exists | +| 3 | UNION RESULT | ** | NULL | ALL | NULL | NULL | NULL | NULL | 0 | n% | ☠️ **O(n)** | Using temporary | @@ -2549,6 +2547,8 @@ WHERE * **PRIMARY**: 最外层的select. +* **UNION RESULT**: UNION查询的结果集. + * **UNION**: UNION中的第二个或后面的SELECT查询, 不依赖于外部查询的结果集. #### Type信息解读 @@ -2565,6 +2565,8 @@ WHERE * **Using where**: WHERE条件用于筛选出与下一个表匹配的数据然后返回给客户端. 除非故意做的全表扫描, 否则连接类型是ALL或者是index, 且在Extra列的值中没有Using Where, 则该查询可能是有问题的. +* ☠️ **Using temporary**: 表示MySQL在对查询结果排序时使用临时表. 常见于排序order by和分组查询group by. + ## 为sakila库的city表添加索引 @@ -3825,7 +3827,7 @@ FROM | 1 | PRIMARY | *o* | NULL | eq\_ref | PRIMARY | PRIMARY | 2 | sakila.i.city\_id | 1 | ☠️ **100.00%** | O(log n) | NULL | | 2 | UNION | *o* | NULL | ALL | NULL | NULL | NULL | NULL | 109 | ☠️ **100.00%** | ☠️ **O(n)** | NULL | | 2 | UNION | *i* | NULL | eq\_ref | PRIMARY | PRIMARY | 2 | sakila.o.country\_id | 1 | ☠️ **100.00%** | O(log n) | NULL | -| 2 | UNION | *i* | NULL | eq\_ref | PRIMARY | PRIMARY | 2 | sakila.o.country\_id | 1 | ☠️ **100.00%** | O(log n) | NULL | +| 3 | UNION RESULT | ** | NULL | ALL | NULL | NULL | NULL | NULL | 0 | n% | ☠️ **O(n)** | Using temporary | @@ -3835,6 +3837,8 @@ FROM * **PRIMARY**: 最外层的select. +* **UNION RESULT**: UNION查询的结果集. + * **UNION**: UNION中的第二个或后面的SELECT查询, 不依赖于外部查询的结果集. #### Type信息解读 @@ -3843,6 +3847,10 @@ FROM * ☠️ **ALL**: 最坏的情况, 从头到尾全表扫描. +#### Extra信息解读 + +* ☠️ **Using temporary**: 表示MySQL在对查询结果排序时使用临时表. 常见于排序order by和分组查询group by. + ## 建议使用 AS 关键字显示声明一个别名 @@ -3993,7 +4001,7 @@ WHERE | 1 | PRIMARY | *o* | NULL | eq\_ref | PRIMARY | PRIMARY | 2 | sakila.i.city\_id | 1 | ☠️ **100.00%** | O(log n) | Using where; Not exists | | 2 | UNION | *o* | NULL | ALL | NULL | NULL | NULL | NULL | 109 | ☠️ **100.00%** | ☠️ **O(n)** | NULL | | 2 | UNION | *i* | NULL | eq\_ref | PRIMARY | PRIMARY | 2 | sakila.o.country\_id | 1 | ☠️ **100.00%** | O(log n) | Using where; Not exists | -| 2 | UNION | *i* | NULL | eq\_ref | PRIMARY | PRIMARY | 2 | sakila.o.country\_id | 1 | ☠️ **100.00%** | O(log n) | Using where; Not exists | +| 3 | UNION RESULT | ** | NULL | ALL | NULL | NULL | NULL | NULL | 0 | n% | ☠️ **O(n)** | Using temporary | @@ -4003,6 +4011,8 @@ WHERE * **PRIMARY**: 最外层的select. +* **UNION RESULT**: UNION查询的结果集. + * **UNION**: UNION中的第二个或后面的SELECT查询, 不依赖于外部查询的结果集. #### Type信息解读 @@ -4017,6 +4027,8 @@ WHERE * **Using where**: WHERE条件用于筛选出与下一个表匹配的数据然后返回给客户端. 除非故意做的全表扫描, 否则连接类型是ALL或者是index, 且在Extra列的值中没有Using Where, 则该查询可能是有问题的. +* ☠️ **Using temporary**: 表示MySQL在对查询结果排序时使用临时表. 常见于排序order by和分组查询group by. + ## 建议使用 AS 关键字显示声明一个别名 @@ -4082,7 +4094,7 @@ FROM # Query: E48A20D0413512DA -★ ★ ☆ ☆ ☆ 40分 +★ ★ ☆ ☆ ☆ 50分 ```sql @@ -4174,14 +4186,6 @@ ORDER BY * **Content:** 在列或表别名(如"tbl AS alias")中, 明确使用 AS 关键字比隐含别名(如"tbl alias")更易懂。 -## ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引 - -* **Item:** CLA.007 - -* **Severity:** L2 - -* **Content:** ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。 - ## 同一张表被连接两次 * **Item:** JOI.002 @@ -4601,7 +4605,7 @@ ORDER BY * **Severity:** L4 -* **Content:** 在 MySQL 8.0之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 +* **Content:** 在 MySQL 8.0 之前当 ORDER BY 多个列指定的排序方向不同时将无法使用已经建立的索引。 # Query: C11ECE7AE5F80CE5