Mysql

使用帶有 order by 的索引進行查詢

  • April 29, 2017

我目前正在使用啟用 mysql 實例的 log_queries_not_using 索引檢查 slow_query_log。有一個查詢非常頻繁地出現,它不是一個慢查詢,而是一個不使用索引的查詢。

查詢具有以下結構:

select ...
from `Tb1`
left join `Tb2` on `Tb1`.`id` = `Tb2`.`id_tb1`
left join `Tb3` on `Tb2`.`id_common` = `Tb3`.`id_common`
left join `Tb4` on `Tb2`.`id` = `Tb4`.`id_tb2`
left join `Tb5` on `Tb1`.`id_tb5` = `Tb5`.`id`;

此查詢的說明如下:

+----+-------------+--------+------------+--------+-----------------+------------------+---------+-----------------------+------+----------+-------------+
| id | select_type | table  | partitions | type   | possible_keys   | key              | key_len | ref                   | rows | filtered | Extra       |
+----+-------------+--------+------------+--------+-----------------+------------------+---------+-----------------------+------+----------+-------------+
|  1 | SIMPLE      | Tb1    | NULL       | ALL    | NULL            | NULL             | NULL    | NULL                  |    1 |   100.00 | NULL        |
|  1 | SIMPLE      | Tb2    | NULL       | ref    | fk_tb2_tb1_idx  | fk_tb2_tb1_idx   | 4       | schema.tb1.id         |    1 |   100.00 | NULL        |
|  1 | SIMPLE      | Tb3    | NULL       | ref    | fk_tb2_tb3_idx  | fk_tb2_tb3_idx   | 4       | schema.Tb2.id_common  |    1 |   100.00 | Using index |
|  1 | SIMPLE      | Tb4    | NULL       | ref    | fk_tb4_tb2_idx  | fk_tb4_tb2_idx   | 4       | schema.Tb2.id         |    1 |   100.00 | NULL        |
|  1 | SIMPLE      | Tb5    | NULL       | eq_ref | PRIMARY         | PRIMARY          | 4       | schema.tb1.id_tb5     |    1 |   100.00 | NULL        |
+----+-------------+--------+------------+--------+-----------------+------------------+---------+-----------------------+------+----------+-------------+

正如我們從解釋的輸出中看到的那樣,查詢不使用 Tb1 上的任何索引,即使它在與其他表連接的列上有索引。

問題 1:

為什麼此查詢不使用 Tb1 表上的索引?

然後,我嘗試使用 Tb1 的 id 使用“order by”,如下所示:

select ...
from `Tb1`
left join `Tb2` on `Tb1`.`id` = `Tb2`.`id_tb1`
left join `Tb3` on `Tb2`.`id_common` = `Tb3`.`id_common`
left join `Tb4` on `Tb2`.`id` = `Tb4`.`id_tb2`
left join `Tb5` on `Tb1`.`id_tb5` = `Tb5`.`id`
order by Tb1.id;

在解釋中得到以下結果:

   +----+-------------+--------+------------+--------+-----------------+-------------------+---------+----------------------+------+----------+-------------+
   | id | select_type | table  | partitions | type   | possible_keys   | key               | key_len | ref                  | rows | filtered | Extra       |
   +----+-------------+--------+------------+--------+-----------------+-------------------+---------+----------------------+------+----------+-------------+
   |  1 | SIMPLE      | Tb1    | NULL       | index  | NULL            | PRIMARY           | 4       | NULL                 |    1 |   100.00 | NULL        |
   |  1 | SIMPLE      | Tb2    | NULL       | ref    | fk_tb2_tb1_idx  | fk_tb2_tb1_idx    | 4       | schema.tb1.id        |    1 |   100.00 | NULL        |
   |  1 | SIMPLE      | Tb3    | NULL       | ref    | fk_tb2_tb3_idx  | fk_tb2_tb3_idx    | 4       | schema.Tb2.id_common |    1 |   100.00 | Using index |
   |  1 | SIMPLE      | Tb4    | NULL       | ref    | fk_tb4_tb2_idx  | fk_tb4_tb2_idx    | 4       | schema.Tb2.id        |    1 |   100.00 | NULL        |
   |  1 | SIMPLE      | Tb5    | NULL       | eq_ref | PRIMARY         | PRIMARY           | 4       | schema.tb1.id_tb5    |    1 |   100.00 | NULL        |
   +----+-------------+--------+------------+--------+-----------------+-------------------+---------+----------------------+------+----------+-------------+

正如我們從解釋號的輸出中看到的那樣。2,它現在使用主鍵作為索引。

問題2:

使用這個順序: a) 會提高查詢的性能嗎?b) 查詢性能相同。c) 會降低查詢的性能嗎?

答案 1:

在內部,在 InnoDB 的情況下,全表掃描與使用主鍵相同,因為 InnoDB 通過主鍵對數據進行集群。而且它不使用任何其他索引,因為第一個表上沒有 WHERE 條件。

答案 2:

實際上,添加order by不會有任何區別,因為執行計劃將基本保持不變(並且返回的結果也將相同)。這又是因為 InnoDB 按主鍵對數據進行集群,即行總是在內部按主鍵排序。

因此,如果在慢查詢日誌中看不到這些查詢讓您感覺更好,請添加 order by。

最後,我知道你沒有問這個,但是 - 我真的建議不要使用log-queries-not-using-indexes它,因為它會讓你把注意力集中在錯誤的指標上。這是我推薦的查詢分析方法:高級 MySQL 慢查詢日誌影片教程

祝你好運!

引用自:https://dba.stackexchange.com/questions/172303