`
vitoer
  • 浏览: 6299 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

explain 优化( 转载)http://blog.csdn.net/wenniuwuren

 
阅读更多
EXPLAIN sql优化方法(2) Using temporary ; Using filesort
航空母舰 2016-05-12 11:20:33 浏览91 评论0
SQLMySQLCC++C#

摘要: 优化GROUP BY语句 默认情况下,MySQL对所有GROUP BY col1,col2...的字段进行排序。这与在查询中指定ORDER BY col1,col2...类似。因此,如果显式包括一个包含相同的列的ORDER BY子句,则对MySQL的实际执行性能没有什么影响。 如果查询包括GR...

优化GROUP BY语句

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

Java代码  收藏代码
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的字段都是升序或者都是降序。


例如:
Java代码  收藏代码
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; 
但是以下的情况不使用索引:
Java代码  收藏代码
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 

Java代码  收藏代码
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做如下改动:

Java代码  收藏代码
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的时候会有以下发现:

Java代码  收藏代码
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:

Java代码  收藏代码
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也没有再出现

Java代码  收藏代码
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次:

Java代码  收藏代码
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的执行效率,并进行定期优化。
分享到:
评论

相关推荐

    Android代码-Motion-ShapeOfView

    Explain how to use MotionLayout with ShapeOfView This project is the sample of a medium article : https://medium.com/p/26a7ab10142f https://github.com/florent37/ShapeOfView dependencies { ...

    SQLite(SqliteDev)

     EXPLAIN  expression  INSERT  ON CONFLICT clause  PRAGMA  REPLACE  ROLLBACK TRANSACTION  SELECT  UPDATE  同时它还支持事务处理功能等等。也有人说它象Microsoft的Access,有时候真的觉得有点象,...

    Hong Kong Weather Extension (香港天氣)-crx插件

    顯示由香港天文台發出的天氣資訊及警告訊號, 並可在警告剛生效或除下時顯示通知。 1. 提供日常大部份所需的天氣資...警告訊號圖示 &gt; http://www.hko.gov.hk/textonly/explain/introc.htm 支持语言:English,中文 (繁體)

    编译eAccelerator.dll 用的bison

    用于编译eAccelerator的编译器 使用说明请见包里说明 相关资料: 在Windows环境下编译、配置 ... ... eAccelerator 配置参数详解: http://www.oaxueyuan.com/eaccelerator-configuration-parameters-explain.html

    eAccelerator.dll for php5.3.8 nts

    bison.exe 下载地址:http://gnuwin32.sourceforge.net/packages/bison.htm(此文附件也提供下载) ———————————————————– 好了,我们现在开始: 第一步、解压下载到得php5.3.6源文件包tar.bz...

    http://localhost:5560/isqlplus/dba 用户设置

    5. **性能监控**:dba用户还负责监控数据库性能,包括查询优化、索引管理、内存配置等。通过isqlplus,可以运行性能分析语句,如EXPLAIN PLAN,以了解查询执行路径。 6. **故障排查**:当遇到问题时,dba需要有能力...

    优化MySql数据库

    MySQL数据库优化是一个综合性的过程,涉及到多个层面,包括配置调整、数据库设计优化、SQL语句优化以及硬件升级等。以下将详细介绍这些方面的优化策略。 一、配置方面 配置文件优化是提升MySQL性能的基础。例如,`...

    Python库 | azureml_explain_model-1.0.41-py3-none-any.whl

    资源分类:Python库 所属语言:Python 资源全名:azureml_explain_model-1.0.41-py3-none-any.whl 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

    笔记-MySQL.pdf

    理解EXPLAIN命令的使用,可以分析查询执行计划,找出性能瓶颈。 5. **InnoDB引擎底层解析**:InnoDB是MySQL中最常用的事务型存储引擎,支持行级锁定和ACID特性。理解其事务处理机制、redo logs、undo logs、MVCC...

    大厂面试-头条,2022年最新资源,祝您斩获高薪offer!

    - **数据库优化**:通过EXPLAIN分析SQL性能,调整索引、优化查询语句等。 7. **微服务与系统设计**: - **微服务循环依赖**:A服务依赖B服务,B服务又依赖A服务,可能导致循环调用,需要避免这种设计。 - **高...

    MySQL学习笔记

    工具如SHOW STATUS、SHOW VARIABLES、EXPLAIN、pt-query-digest等用于监控MySQL性能。调优包括优化查询、调整系统参数、使用合适的硬件等。 12. **复制与集群** MySQL复制允许数据在多个服务器间同步,提高可用性...

    6天掌握mysql基础视频教程.rar

    同时,会讲解SQL查询的优化,如分析执行计划,使用EXPLAIN命令,以及避免全表扫描。 5. **事务处理**: 了解事务的基本概念,包括ACID(原子性、一致性、隔离性、持久性)属性,以及如何使用BEGIN、COMMIT和...

    MySQL索引检查.docx

    MySQL索引检查是数据库优化的重要环节...同时,使用`EXPLAIN`关键字来分析SQL查询的执行计划,可以帮助我们了解索引的效果,从而进行优化。在实际工作中,定期进行索引检查和调整,可以显著提高数据库系统的整体性能。

    mysql开发规范,mysql优化指南

    对于性能要求高的操作,推荐使用EXPLAIN分析SQL执行计划,以便及时发现和优化问题。 此外,规范还包括了其他一些重要建议,比如使用合适的日期和时间类型、避免使用复杂的表达式、优化排序和分组操作等。 文档还...

    mysql必知必会

    理解B-Tree、Hash和Full-text等不同类型的索引,以及如何使用EXPLAIN分析查询执行计划,能优化查询性能。 5. **视图**:视图是虚拟表,基于一个或多个表的查询结果。它提供了数据的抽象,简化复杂查询并保护底层...

    高性能Mysql 第三版 高清

    《高性能MySQL》第三版是一本深受数据库管理员、开发人员及系统架构师喜爱的经典著作,它深入探讨了如何优化和管理MySQL数据库系统以实现高性能。这本书的高清版本提供了更清晰的阅读体验,确保读者能够准确理解其中...

    mysql高频经典面试题

    MySQL是世界上最流行的开源关系型数据库管理系统之一,广泛应用于各种规模的企业和项目中。...在实际应用中,应根据具体业务需求选择合适的数据库设计原则、索引策略和事务隔离级别,以优化性能和保证数据一致性。

    云平台开发人员MySQL数据库知识手册

    - 使用`EXPLAIN`分析执行计划 - **第七章:应用性能优化** - 应用层缓存策略 - 连接池管理 - 错误处理机制 - **第八章:安全性与备份恢复** - 用户权限管理 - 数据加密技术 - 备份策略与灾难恢复方案 - **第...

Global site tag (gtag.js) - Google Analytics