`
hudeyong926
  • 浏览: 2023068 次
  • 来自: 武汉
社区版块
存档分类
最新评论

EXPLAIN sql优化方法(2) Using temporary ; Using filesort

阅读更多

主要针对where,group by, order by子句优化

优化GROUP BY语句

默认情况下,MySQL对所有GROUP BY col1,col2...的字段进行排序。这与在查询中指定ORDER BY col1,col2...类似。因此,如果显式包括一个包含相同的列的ORDER BY子句,则对MySQL的实际执行性能没有什么影响。 如果查询包括GROUP BY 但用户想要避免排序结果的消耗,则可以指定ORDER By NULL禁止排序,例如:

explain select id, sum(moneys) from sales2 group by id \G   
explain select id, sum(moneys) from sales2 group by id order by null \G 
你可以通过比较发现第一条语句会比第二句在Extra:里面多了Using filesort.而恰恰filesort是最耗时的。

 

优化ORDER BY语句

在某些情况中,MySQL可以使用一个索引来满足ORDER BY子句,而不需要额外的排序。WHERE 条件和 ORDER BY使用相同的索引,并且ORDER BY的顺序和索引顺序相同,并且ORDER BY的字段都是升序或者都是降序。


例如:
SELECT * FROM t1 ORDER BY key_part1,key_part2,....:
SELECT * FROM t1 WHERE key_part1 = 1 ORDER BY key_part1 DESC,key_part2 DESC;
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
但是以下的情况不使用索引:
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
--ORDER by的字段混合ASC 和 DESC
SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
 ----用于查询行的关键字与ORDER BY 中所使用的不相同
 SELECT * FROM t1 ORDER BY key1, key2;
 ----对不同的关键字使用ORDER BY
 
 mysql > explain select A . id , A . title , B . title from jos_content A left join jos_categories B on A . catid = B . id left join jos_sections C on A . sectionid = C . id order by B . id ;
+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+---------------------------------+
| id | select_type | table | type    | possible_keys | key      | key_len | ref                      | rows   | Extra                            |
+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+---------------------------------+
|  1 | SIMPLE       | A      | ALL     | NULL           | NULL     | NULL     | NULL                     | 46585 | Using temporary ; Using filesort |
|  1 | SIMPLE       | B      | eq_ref | PRIMARY        | PRIMARY | 4        | joomla_test . A . catid      |      1 |                                 |
|  1 | SIMPLE       | C      | eq_ref | PRIMARY        | PRIMARY | 4        | joomla_test . A . sectionid |      1 | Using index                      |
+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+---------------------------------+
3 rows in set ( 0.00 sec )
 
mysql > explain select A . id , A . title , B . title from jos_content A left join jos_categories B on A . catid = B . id left join jos_sections C on A . sectionid = C . id order by A . id ;
+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+----------------+
| id | select_type | table | type    | possible_keys | key      | key_len | ref                      | rows   | Extra           |
+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+----------------+
|  1 | SIMPLE       | A      | ALL     | NULL           | NULL     | NULL     | NULL                     | 46585 | Using filesort |
|  1 | SIMPLE       | B      | eq_ref | PRIMARY        | PRIMARY | 4        | joomla_test . A . catid      |      1 |                |
|  1 | SIMPLE       | C      | eq_ref | PRIMARY        | PRIMARY | 4        | joomla_test . A . sectionid |      1 | Using index     |
+----+-------------+-------+--------+---------------+---------+---------+-------------------------+-------+----------------+
 对于上面两条语句,只是修改了一下排序字段,而第一个使用了Using temporary,而第二个却没有。在日常的网站维护中,如果有Using temporary出现,说明需要做一些优化措施了。

而为什么第一个用了临时表,而第二个没有用呢?
因为如果有ORDER BY子句和一个不同的GROUP BY子句,或者如果ORDER BY或GROUP BY中的字段都来自其他的表而非连接顺序中的第一个表的话,就会创建一个临时表了。
那么,对于上面例子中的第一条语句,我们需要对jos_categories的id进行排序,可以将SQL做如下改动:

mysql > explain select B . id , B . title , A . title from jos_categories A left join jos_content B on A . id = B . catid left join jos_sections C on B . sectionid = C . id order by A . id ;
+----+-------------+-------+--------+---------------+-----------+---------+-------------------------+------+----------------+
| id | select_type | table | type    | possible_keys | key        | key_len | ref                      | rows | Extra           |
+----+-------------+-------+--------+---------------+-----------+---------+-------------------------+------+----------------+
|  1 | SIMPLE       | A      | ALL     | NULL           | NULL       | NULL     | NULL                     |    18 | Using filesort |
|  1 | SIMPLE       | B      | ref     | idx_catid      | idx_catid | 4        | joomla_test . A . id         | 3328 |                |
|  1 | SIMPLE       | C      | eq_ref | PRIMARY        | PRIMARY    | 4        | joomla_test . B . sectionid |    1 | Using index     |
+----+-------------+-------+--------+---------------+-----------+---------+-------------------------+------+----------------+
3 rows in set ( 0.00 sec )

这样我们发现,不会再有Using temporary了,而且在查询jos_content时,查询的记录明显有了数量级的降低,这是因为jos_content的idx_catid起了作用。
所以结论是:

尽量对第一个表的索引键进行排序,这样效率是高的。
我们还会发现,在排序的语句中都出现了Using filesort,字面意思可能会被理解为:使用文件进行排序或中文件中进行排序。实际上这是不正确的,这是一个让人产生误解的词语。
当我们试图对一个没有索引的字段进行排序时,就是filesoft。它跟文件没有任何关系,实际上是内部的一个快速排序。
然而,当我们回过头来再看上面运行过的一个SQL的时候会有以下发现:

mysql > explain select A . id , A . title , B . title from jos_content A , jos_categories B , jos_sections C where A . catid = B . id and A . sectionid = C . id order by C . id ;
+----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+
| id | select_type | table | type    | possible_keys          | key          | key_len | ref                  | rows   | Extra        |
+----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+
|  1 | SIMPLE       | C      | index   | PRIMARY                | PRIMARY      | 4        | NULL                 |      1 | Using index |
|  1 | SIMPLE       | A      | ref     | idx_catid , idx_section | idx_section | 4        | joomla_test . C . id     | 23293 | Using where |
|  1 | SIMPLE       | B      | eq_ref | PRIMARY                | PRIMARY      | 4        | joomla_test . A . catid |      1 | Using where |
+----+-------------+-------+--------+-----------------------+-------------+---------+---------------------+-------+-------------+
3 rows in set ( 0.00 sec )

这是我们刚才运行过的一条语句,只是加了一个排序,而这条语句中C表的主键对排序起了作用,我们会发现Using filesort没有了。
而尽管在上面的语句中也是对第一个表的主键进行排序,却没有得到想要的效果(第一个表的主键没有用到),这是为什么呢?实际上以上运行过的所有left join的语句中,第一个表的索引都没有用到,尽管对第一个表的主键进行了排序也无济于事。不免有些奇怪!

于是我们继续测试了下一条SQL:

mysql > explain select A . id , A . title , B . title from jos_content A left join jos_categories B on A . catid = B . id left join jos_sections C on A . sectionid = C . id where A . id < 100 ;
+----+-------------+-------+--------+----------------+---------+---------+-------------------------+------+-------------+
| id | select_type | table | type    | possible_keys   | key      | key_len | ref                      | rows | Extra        |
+----+-------------+-------+--------+----------------+---------+---------+-------------------------+------+-------------+
|  1 | SIMPLE       | A      | range   | PRIMARY         | PRIMARY | 4        | NULL                     |    90 | Using where |
|  1 | SIMPLE       | B      | eq_ref | PRIMARY         | PRIMARY | 4        | joomla_test . A . catid      |    1 |             |
|  1 | SIMPLE       | C      | eq_ref | PRIMARY         | PRIMARY | 4        | joomla_test . A . sectionid |    1 | Using index |
+----+-------------+-------+--------+----------------+---------+---------+-------------------------+------+-------------+
3 rows in set ( 0.05 sec )

然后,当再次进行排序操作的时候,Using filesoft也没有再出现

mysql > explain select A . id , A . title , B . title from jos_content A left join jos_categories B on A . catid = B . id left join jos_sections C on A . sectionid = C . id where A . id < 100 order by A . id ;
+----+-------------+-------+--------+---------------+---------+---------+-------------------------+------+-------------+
| id | select_type | table | type    | possible_keys | key      | key_len | ref                      | rows | Extra        |
+----+-------------+-------+--------+---------------+---------+---------+-------------------------+------+-------------+
|  1 | SIMPLE       | A      | range   | PRIMARY        | PRIMARY | 4        | NULL                     |  105 | Using where |
|  1 | SIMPLE       | B      | eq_ref | PRIMARY        | PRIMARY | 4        | joomla_test . A . catid      |    1 |             |
|  1 | SIMPLE       | C      | eq_ref | PRIMARY        | PRIMARY | 4        | joomla_test . A . sectionid |    1 | Using index |
+----+-------------+-------+--------+---------------+---------+---------+-------------------------+------+-------------+
3 rows in set ( 0.00 sec )

这个结果表明:对where条件里涉及到的字段,Mysql会使用索引进行搜索,而这个索引的使用也对排序的效率有很好的提升。
写了段程序测试了一下,分别让以下两个SQL语句执行200次:

select A . id , A . title , B . title from jos_content   A left join jos_categories B on A . catid = B . id left join jos_sections C   on A . sectionid = C . id
select A . id , A . title , B . title from jos_content   A , jos_categories B , jos_sections C where A . catid = B . id and   A . sectionid = C . id
select A . id , A . title , B . title from jos_content A left   join jos_categories B on A . catid = B . id left join jos_sections C on   A . sectionid = C . id   order by rand () limit 10
select A . id from   jos_content A left join jos_categories B on B . id = A . catid left join   jos_sections C on A . sectionid = C . id order by A . id

结果是第(1)条平均用时20s ,第(2)条平均用时44s ,第(3)条平均用时70s ,第(4)条平均用时2s 。而且假如我们用explain观察第(3)条语句的执行情况,会发现它创建了temporary表来进行排序。

综上所述,可以得出如下结论:
1. 对需要查询和排序的字段要加索引。
2. 在一定环境下,left join还是比普通连接查询效率要高,但是要尽量少地连接表,并且在做连接查询时注意观察索引是否起了作用。
3. 排序尽量对第一个表的索引字段进行,可以避免mysql创建临时表,这是非常耗资源的。
4. 对where条件里涉及到的字段,应适当地添加索引,这样会对排序操作有优化的作用。
5. 在做随机抽取数据的需求时,避免使用order by rand(),从上面的例子可以看出,这种是很浪费数据库资源的,在执行过程中用show processlist查看,会发现第(3)条有Copying to tmp table on disk。而对(3)和(4)的对比得知,如果要实现这个功能,最好另辟奚径,来减轻Mysql的压力。
6. 从第4点可以看出,如果说在分页时我们能先得到主键,再根据主键查询相关内容,也能得到查询的优化效果。通过国外《High Performance MySQL》专家组的测试可以看出,根据主键进行查询的类似“SELECT ... FROM... WHERE id = ...”的SQL语句(其中id为PRIMARYKEY),每秒钟能够处理10000次 以上的查询,而普通的SELECT查询每秒只能处理几十次到几百次 。涉及到分页的查询效率问题,网上的可用资源越来越多,查询功能也体现出了它的重要性。也便是sphinx、lucene这些第三方搜索引擎的用武之地了。
7. 在平时的作业中,可以打开Mysql的Slow queries功能,经常检查一下是哪些语句降低的Mysql的执行效率,并进行定期优化。

分享到:
评论

相关推荐

    【mysql知识点整理】— order by 、group by 出现Using filesort原因详解

    文章目录测试数据1 sql执行顺序2 order by 和 group by什么时候会出现Using filesort — 理论3 order by 和 group by什么时候会出现Using filesort — 实践3.1 不会出现 Using filesort的情况 — 符合最佳左前缀法则...

    mysql的explain分析sql语句性能(慢查询和加没加索引)

    10. Extra:额外的重要信息,常见且重要的有:using filesort(文件内排序,MySQL 无法用给定的索引进行排序,在内部重新排序)、using temporary(使用了临时表,一般在 group by 中),using index(最好的一种,...

    sql优化思路.pptx

    - **extra**:包含了关于查询执行的额外信息,例如`Using filesort`表示需要进行额外的排序操作,`Using index`表示使用了覆盖索引,`Using temporary`则表示使用了临时表,这些都是可能的性能瓶颈。 3. **PROFILE...

    程序员必备:SQL优化技巧

    - **extra**:包含像`Using filesort`(需要额外的排序操作)、`Using temporary`(使用临时表)等信息,这些通常表明性能问题。 3. **索引优化**: - 确保使用正确的索引,比如在`WHERE`子句中涉及的列上创建...

    mysql+explain实例分析

    10. **Extra**:包含MySQL解决查询的额外信息,如“Using where”、“Using filesort”和“Using temporary”。 通过分析`EXPLAIN`的结果,我们可以发现查询优化的机会。例如,如果看到"Using filesort",表示MySQL...

    Explain详解与索引最佳实践.pdf

    10. **extra** 列:提供关于MySQL如何优化查询的其他信息,如`Using where`、`Using index`、`Using temporary`、`Using filesort`等。`Using index`表示使用了覆盖索引,而`Using filesort`表示数据需要额外排序,...

    行业-103 透彻研究通过explain命令得到的SQL执行计划(4).rar

    - `Extra`中出现`Using temporary`表示使用了临时表,`Using filesort`表示进行了文件排序,这些都会增加查询的资源消耗,应尽量避免。 通过分析`EXPLAIN`输出,我们可以针对性地调整索引、优化查询结构,甚至重构...

    行业-101 透彻研究通过explain命令得到的SQL执行计划(2).rar

    10. **Extra**:提供额外的信息,如`Using where`表示在索引的帮助下进行了过滤,`Using filesort`表示需要对结果进行额外的排序操作,而`Using temporary`表示需要创建临时表来完成查询。 理解了这些概念后,我们...

    行业-107 透彻研究通过explain命令得到的SQL执行计划(8).rar

    - **减少临时表的使用**:避免使用`filesort`和`using temporary`,这通常意味着数据需要被排序或存储到临时表中。 - **避免子查询**:子查询可能导致多次表扫描,尝试转化为连接操作以提高效率。 3. **深入理解...

    Explain详解与索引最佳实践1

    在进行性能优化时,我们通常希望看到`type`列为`const`或`ref`,`key`列为实际的索引名,`rows`数值尽可能小,以及避免`Using temporary`和`Using filesort`。如果发现这些指标不尽如人意,可能需要调整索引策略,...

    mysqlexplain-100712043803-phpapp01.ppt

    看到Extra中的Using filesort或Using temporary,意味着可能需要调整JOIN顺序或添加索引。 六、总结 掌握`EXPLAIN`工具的使用,是每个MySQL数据库管理员和开发者必备的技能。通过深入理解查询执行计划,我们可以更...

    mysql性能优化.pptx

    注意`Extra`列中的`Using filesort`和`Using temporary table`,这些表明了MySQL需要额外的资源进行排序或创建临时表,可能是优化的焦点。 3. **索引优化** - 选择合适的列建立索引:考虑选择具有高选择性的列,即...

    mysql开启慢查询(EXPLAIN SQL语句使用介绍)

    - `Extra`:额外信息,如`Using where`、`Using index`、`Using temporary`和`Using filesort`。 理解`key_len`的计算对优化索引至关重要。计算规则如下: 1. 非`NULL`字段会额外占用一个字节。 2. 定长字段,如`...

    MySQL查询语句过程和EXPLAIN语句基本概念及其优化

    例如,一个查询可能显示`Using filesort`和`Using temporary`,这通常意味着查询优化的机会。可以通过重新构造查询语句,或者添加合适的索引来避免这些问题。例如,如果查询需要对大量数据进行排序,可以尝试先对...

    查询优化之EXPLAIN的使用分析

    `EXPLAIN`命令是数据库管理员和开发者用来理解查询执行计划的工具,它可以帮助我们分析SQL语句的执行过程,从而找到可能存在的性能瓶颈并进行优化。下面我们将深入探讨`EXPLAIN`的使用方法及其各个字段的含义。 1. ...

    Mysql Explain 详细介绍

    - 注意`Extra`列中的`Using where`、`Using filesort`和`Using temporary`,这些都可能影响性能。 4. **实例代码** 下面的例子展示了如何使用EXPLAIN来分析查询: ```sql EXPLAIN SELECT * FROM t3 WHERE id = ...

    详解MySQL中EXPLAIN解释命令及用法讲解

    MySQL中的EXPLAIN命令是数据库管理员和开发者用于分析和优化SQL查询的重要工具。它能帮助我们理解MySQL如何执行SELECT语句,特别是在涉及多个表连接和索引使用时。下面是对EXPLAIN命令及其各列的详细解释。 1. **...

    mysql总结之explain

    通过分析`EXPLAIN`的结果,我们可以优化SQL查询,比如添加合适的索引,减少全表扫描,避免`filesort`和`temporary table`的使用,以提高查询效率。理解并熟练运用`EXPLAIN`,是数据库性能调优的关键步骤。

    MySQL中执行计划explain命令示例详解

    10. **Extra** - 提供额外信息,如`Using where`, `Using index`, `Using temporary`, `Using filesort`等。这些信息可以帮助我们理解查询的执行过程。 `EXPLAIN EXTENDED`和`EXPLAIN PARTITIONS`是`EXPLAIN`的扩展...

    MYSQL explain 执行计划

    MySQL的`EXPLAIN`命令是数据库管理员和开发者用于分析SQL查询执行计划的重要工具。通过`EXPLAIN`,我们可以深入理解MySQL如何...在编写SQL查询时,结合`EXPLAIN`的输出,可以针对性地进行优化,提升数据库的运行效率。

Global site tag (gtag.js) - Google Analytics