Using temporary和Using filesort分析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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快,因为索引文件通常比数据文件小。

本文出自 “南山深处” 博客,请务必保留此出处http://kenneyzhou.blog.51cto.com/12427643/1889429

以上是关于Using temporary和Using filesort分析的主要内容,如果未能解决你的问题,请参考以下文章

优化查询,去掉“Using where;Using temporary;Using filesort”

mysql using filesort Using temporary

EXPLAIN sql优化方法 Using temporary ; Using filesort

EXPLAIN sql优化方法 Using temporary ; Using filesort

从查询执行中删除 using temporary 和 Filesort

优化 MySQL 连接查询以删除 Using temporary 并使用索引?