Using temporary和Using filesort分析

mysql> show create table t1;
+-------+----------------------------------
| Table | Create Table                                            
+-------+--------------------------------
| t1    | CREATE TABLE `t1` (
 `id` int(11) NOT NULL DEFAULT '0',
 `age` int(11) DEFAULT NULL,
 `name` varchar(32) DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `age_1` (`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+---------------------------------
1 row in set (0.00 sec)

1 測試order by使用索引的情況
#按主鍵id進行排序,走的是主鍵索引。主鍵索引b+tree,葉子節點(存儲的是行數據)是按照主鍵索引順序組織的。
mysql> desc select * from t1 order by id;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
|  1 | SIMPLE      | t1    | index | NULL          | PRIMARY | 4       | NULL |    9 | NULL  |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
1 row in set (0.00 sec)

#按普通索引age排序,走的是全表掃描。他之所以沒有走普通索引,是因爲如果用filesort排序代價更小。
如果走普通索引,先走二級索引b+tree,找到對應的主鍵key;再走主鍵索引數,找到葉子節點主鍵值對應的行記錄。
mysql> desc select * from t1 order by age;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | t1    | ALL  | NULL          | NULL | NULL    | NULL |    9 | Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)
不讓查詢優化器自己選擇,強制使用索引。
mysql> desc select * from t1 force index(age) order by age;
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------+
|  1 | SIMPLE      | t1    | index | NULL          | age_1 | 5       | NULL |    9 | NULL  |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------+
1 row in set (0.00 sec)
#不使用索引的字段排序
mysql> desc select * from t1 order by name;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | t1    | ALL  | NULL          | NULL | NULL    | NULL |    9 | Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)
=========================================================================
如果select column 裏面的column加了索引,不需要回表, 直接using index。
#查詢id字段,id是主鍵,useing index,不回表。
mysql> desc select id from t1 order by age;
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
|  1 | SIMPLE      | t1    | index | NULL          | age_1 | 5       | NULL |    9 | Using index |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
1 row in set (0.00 sec)

#查詢age字段,普通索引,useing index,不回表。
mysql> desc select age from t1 order by age;  
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
|  1 | SIMPLE      | t1    | index | NULL          | age_1 | 5       | NULL |    9 | Using index |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
1 row in set (0.00 sec)
=========================================================================
2 group by 測試
mysql> desc select * from t1 group by id;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
|  1 | SIMPLE      | t1    | index | PRIMARY,age_1 | PRIMARY | 4       | NULL |    9 | NULL  |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------+
1 row in set (0.00 sec)

mysql> desc select * from t1 group by age;
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------+
| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------+
|  1 | SIMPLE      | t1    | index | age_1         | age_1 | 5       | NULL |    9 | NULL  |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------+
1 row in set (0.00 sec)

#如果排序字段沒有索引,則extra 會出現 Using temporary; Using filesort

#默認group by 會自動按照by後邊的字段進行排序,這樣增加了系統消耗,可以取消默認排序。見下邊實驗
mysql> desc select * from t1 group by name ;
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                           |
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
|  1 | SIMPLE      | t1    | ALL  | NULL          | NULL | NULL    | NULL |    9 | Using temporary; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+---------------------------------+
1 row in set (0.00 sec)
mysql> desc select * from t1 group by name order by null;
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra           |
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------+
|  1 | SIMPLE      | t1    | ALL  | NULL          | NULL | NULL    | NULL |    9 | Using temporary |
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------+
1 row in set (0.00 sec)


#未去掉默認排序
mysql>  select * from t1 group by name;
+----+------+--------+
| id | age  | name   |
+----+------+--------+
|  7 |    0 | aaaa   |
|  1 |    0 | kenney |
|  5 |    0 | tttt   |
+----+------+--------+
3 rows in set (0.00 sec)

#去掉默認排序後
mysql>  select * from t1 group by name order by null;    
+----+------+--------+
| id | age  | name   |
+----+------+--------+
|  1 |    0 | kenney |
|  5 |    0 | tttt   |
|  7 |    0 | aaaa   |
+----+------+--------+
3 rows in set (0.00 sec)


備註:
儘量按索引鍵進行排序,這樣效率會很高。 
我們還會發現,在排序的語句中都出現了Using filesort,字面意思可能會被理解爲:使用文件進行排序或中文件中進行排序。實際上這是不正確的,這是一個讓人產生誤解的詞語。 
當我們試圖對一個沒有索引的字段進行排序時,就是filesoft。它跟文件沒有任何關係,實際上是內部的一個快速排序。

執行計劃關鍵字解析:
extra字段中
Using filesort
MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
Using index
從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
Using temporary
爲了解決查詢,MySQL需要創建一個臨時表來容納結果。

type字段中
ref
對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取
ALL
完全沒有索引的情況,性能非常地差勁。
index
與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因爲索引文件通常比數據文件小。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章