Mysql
使用帶有 order by 的索引進行查詢
我目前正在使用啟用 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 慢查詢日誌影片教程。祝你好運!