MySql學習筆記(八):explain之extra

extra主要有是那種狀況:Using index、Using filesort、Using temporary、Using wherejava

Using where無需多說,就是使用了where篩選條件。mysql

數據準備:sql

CREATE TABLE `t_blog` (
  `id` int(11) NOT NULL auto_increment,
  `title` varchar(50) default NULL,
  `typeId` int(11) default NULL,
  `a` int(11) default '0',
  PRIMARY KEY  (`id`),
  KEY `index_1` (`title`,`typeId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

一、Using indexmysql優化

表示在查詢中使用了覆蓋索引,避免了掃描表的數據行。ide

mysql> EXPLAIN select title from t_blog;
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | t_blog | index | NULL          | index_1 | 158     | NULL |    7 | Using index |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
1 row in set

已知title字段是index_1索引的一部分,上條sql只查詢title字段,只會掃描索引文件而不會掃描表的全部數據行,在extra列中,出現了Using index。性能

mysql> EXPLAIN select * from t_blog;
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | t_blog | ALL  | NULL          | NULL | NULL    | NULL |    7 |       |
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
1 row in set

上條語句中,除了查詢已經加了索引的字段,還查詢了沒有加索引的字段【a】,致使掃描了表的數據行,所以,extra列中沒有出現Using index。優化

當只出現Using index,沒出現Using where時,表示索引用於讀取數據,以第一條sql爲例。blog

當Using index 和 Using where同時出現時,表示索引用於查找動做,例如:排序

mysql> EXPLAIN select title from t_blog where title = 'java';
+----+-------------+--------+------+---------------+---------+---------+-------+------+--------------------------+
| id | select_type | table  | type | possible_keys | key     | key_len | ref   | rows | Extra                    |
+----+-------------+--------+------+---------------+---------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | t_blog | ref  | index_1       | index_1 | 153     | const |    1 | Using where; Using index |
+----+-------------+--------+------+---------------+---------+---------+-------+------+--------------------------+
1 row in set

二、Using filesort索引

Using filesort一般出如今order by,當試圖對一個不是索引的字段進行排序時,mysql就會自動對該字段進行排序,這個過程就稱爲「文件排序」

mysql> EXPLAIN select * from t_blog order by title;
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------+
|  1 | SIMPLE      | t_blog | index | NULL          | index_1 | 158     | NULL |    7 |       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------+
1 row in set

已知title是index_1索引中的第一列索引,因此單獨使用時索引生效,在排序時根據索引排序,不會產生文件排序。

mysql> EXPLAIN select * from t_blog order by typeId;
+----+-------------+--------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+--------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | t_blog | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using filesort |
+----+-------------+--------+------+---------------+------+---------+------+------+----------------+
1 row in set

雖然typeId是index_1索引的第二列,但因爲缺失第一列,因此索引失效。在排序時沒法根據索引排序,故mysql會自動進行排序,產生文件排序。

mysql> EXPLAIN select * from t_blog order by a;
+----+-------------+--------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+--------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | t_blog | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using filesort |
+----+-------------+--------+------+---------------+------+---------+------+------+----------------+
1 row in set

字段a上沒有任何索引,因此在排序時沒法根據索引排序,所以產生文件排序。

Using filesort出現的狀況:排序時沒法根據索引進行排序,mysql優化器只能本身進行排序,這種狀況會大大下降性能,不可取。

三、Using temporary

表示在查詢過程當中產生了臨時表用於保存中間結果。mysql在對查詢結果進行排序時會使用臨時表,常見於group by。

group by的實質是先排序後分組,同order by同樣,group by和索引息息相關。

試圖對一個沒有索引的字段進行分組,會產生臨時表:

mysql> EXPLAIN select title from t_blog group by typeId;
+----+-------------+--------+-------+---------------+---------+---------+------+------+----------------------------------------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra                                        |
+----+-------------+--------+-------+---------------+---------+---------+------+------+----------------------------------------------+
|  1 | SIMPLE      | t_blog | index | NULL          | index_1 | 158     | NULL |    7 | Using index; Using temporary; Using filesort |
+----+-------------+--------+-------+---------------+---------+---------+------+------+----------------------------------------------+
1 row in set

對一個有索引的字段進行分組就不會產生臨時表:

mysql> EXPLAIN select title from t_blog group by title,typeId;
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | t_blog | index | NULL          | index_1 | 158     | NULL |    7 | Using index |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
1 row in set

當order by子句和group by子句的字段相同時不會產生臨時表:

mysql> explain select * from t_blog b left join t_type t on b.typeId = t.id group by b.id order by b.id;
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref           | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------+
|  1 | SIMPLE      | b     | index  | NULL          | PRIMARY | 4       | NULL          |    7 |       |
|  1 | SIMPLE      | t     | eq_ref | PRIMARY       | PRIMARY | 4       | blog.b.typeId |    1 |       |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------+
2 rows in set

當order by子句和group by子句的字段不一樣時就會產生臨時表:

mysql> explain select * from t_blog b left join t_type t on b.typeId = t.id group by b.id order by b.title;
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-----------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref           | rows | Extra           |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-----------------+
|  1 | SIMPLE      | b     | index  | NULL          | index_1 | 158     | NULL          |    7 | Using temporary |
|  1 | SIMPLE      | t     | eq_ref | PRIMARY       | PRIMARY | 4       | blog.b.typeId |    1 |                 |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-----------------+
2 rows in set

當時用left join時,若order by子句和group by子句都來自於從表時會產生臨時表:

mysql> explain select * from t_blog b left join t_type t on b.typeId = t.id group by t.id order by t.id;
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+---------------------------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref           | rows | Extra                           |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+---------------------------------+
|  1 | SIMPLE      | b     | ALL    | NULL          | NULL    | NULL    | NULL          |    7 | Using temporary; Using filesort |
|  1 | SIMPLE      | t     | eq_ref | PRIMARY       | PRIMARY | 4       | blog.b.typeId |    1 |                                 |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+---------------------------------+
2 rows in set
mysql> explain select * from t_blog b left join t_type t on b.typeId = t.id group by t.id order by t.name;
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+---------------------------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref           | rows | Extra                           |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+---------------------------------+
|  1 | SIMPLE      | b     | ALL    | NULL          | NULL    | NULL    | NULL          |    7 | Using temporary; Using filesort |
|  1 | SIMPLE      | t     | eq_ref | PRIMARY       | PRIMARY | 4       | blog.b.typeId |    1 |                                 |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+---------------------------------+
2 rows in set

出現Using temporary意味着產生了臨時表存儲中間結果而且最後刪掉了該臨時表,這個過程很消耗性能。

相關文章
相關標籤/搜索