MySQL 数据库Query 的优化.docx

上传人:飞****2 文档编号:56714224 上传时间:2022-11-03 格式:DOCX 页数:44 大小:1.45MB
返回 下载 相关 举报
MySQL 数据库Query 的优化.docx_第1页
第1页 / 共44页
MySQL 数据库Query 的优化.docx_第2页
第2页 / 共44页
点击查看更多>>
资源描述

《MySQL 数据库Query 的优化.docx》由会员分享,可在线阅读,更多相关《MySQL 数据库Query 的优化.docx(44页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、MySQL 数据库Query 的优化MySQL的Query Opt imi zerMySQL Query Optimizer是什么?在MySQL 中有一个专门负责优化SELECT 语句的优化器模块,我们将要重点分析的MySQL Optimizer,其主要的功能就是通过计算分析系统中收集的各种统计信息,为客户端请求的Query 给出他认为最优的执行计划,也就是他认为最优的数据检索方式。当MySQL Optimizer 接收到从Query Parser (解析器)送过来的Query 之后,会根据MySQLQuery 语句的相应语法对该Query 进行分解分析的同时,还会做很多其他的计算转化工作。如

2、常量转化,无效内容删除,常量计算等等。所有这些工作都只为了Optimizer 工作的唯一目的,分析出最优的数据检索方式,也就是我们常说的执行计划。MySQL Query Optimizer基本工作原理在分析MySQL Optimizer 的工作原理之前,先了解一下MySQL 的Query Tree。MySQL 的Query Tree是通过优化实现DBXP 的经典数据结构和Tree 构造器而生成的一个指导完成一个Query 语句的请求所需要处理的工作步骤,我们可以简单的认为就是一个的数据处理流程规划,只不过是以一个Tree 的数据结构存放而已。通过Query Tree 我们可以很清楚的知道一个Q

3、uery 的完成需要经过哪些步骤的处理,每一步的数据来源在哪里,处理方式是怎样的。在整个DBXP 的Query Tree 生成过程中,MySQL 使用了LEX 和YACC 这两个功能非常强大的语法(词法)分析工具。MySQL Query Optimizer 的所有工作都是基于这个Query Tree 所进行的。各位读者朋友如果对MySQL Query Tree 实现生成的详细信息比较感兴趣,可以参考Chales A. Bell 的Expert MySQL这本书,里面有比较详细的介绍。MySQL Query Optimizer 并不是一个纯粹的CBO(Cost Base Optimizer),而

4、是在CBO 的基础上增加了一个被称为Heuristic Optimize(启发式优化)的功能。也就是说,MySQL Query Optimizer 在优化一个Query 选择出他认为的最优执行计划的时候,并不一定完全按照系数据库的元信息和系统统计信息,而是在此基础上增加了某些特定的规则。其实我个人的理解就是在CBO 的实现中增加了部分RBO(Rule Base Optimizer)的功能,以确保在某些特别的场景下控制Query 按照预定的方式生成执行计划。当客户端向MySQL 请求一条Query ,到命令解析器模块完成请求分类区别出是SELECT 并转发给Query Optimizer 之后,

5、Query Optimizer 首先会对整条Query 进行,优化处理掉一些常量表达式的预算,直接换算成常量值。并对Query 中的查询条件进行简化和转换,如去掉一些无用或者显而易见的条件,结构调整等等。然后则是分析Query 中的Hint 信息(如果有),看显示Hint 信息是否可以完全确定该Query 的执行计划。如果没有Hint 或者Hint 信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据Query 进行写相应的计算分析,然后再得出最后的执行计划。Query Optimizer 是一个数据库软件非常核心的功能,虽然在这里说起来只是简单的几句话,但是在MySQL 内部,Q

6、uery Optimizer 实际上是经过了很多复杂的运算分析,才得出最后的执行计划。对于MySQL Query Optimizer 更多的信息,可以通过MySQL Internal 文档进行更为全面的了解。Query语句优化基本思路和原则在分析如何优化MySQL Query 之前,我们需要先了解一下Query 语句优化的基本思路和原则。一般来说,Query 语句的优化思路和原则主要提现在以下几个方面:1. 优化更需要优化的Query;2. 定位优化对象的性能瓶颈;3. 明确的优化目标;4. 从Explain 入手;5. 多使用profile6. 永远用小结果集驱动大的结果集;7. 尽可能在索

7、引中完成排序;8. 只取出自己需要的Columns;9. 仅仅使用最有效的过滤条件;10. 尽可能避免复杂的Join 和子查询;上面所列的几点信息,前面4 点可以理解为Query 优化的一个基本思路,后面部分则是我们优化中的基本原则。下面我们先针对Query 优化的基本思路做一些简单的分析,理解为什么我们的Query 优化到底该如何进行。优化更需要优化的Query为什么我们需要优化更需要优化的Query?这个地球人都知道的“并不能成为问题的问题”我想就并不需要我过多解释吧那什么样的Query 是更需要优化呢?对于这个问题我们需要从对整个系统的影响来考虑。什么Query 的优化能给系统整体带来更

8、大的收益,就更需要优化。一般来说,高并发低消耗(相对)的Query 对整个系统的影响远比低并发高消耗的Query 大。我们可以通过以下一个非常简单的案例分析来充分说明问题。假设有一个Query 每小时执行10000 次,每次需要20 个IO。另外一个Query 每小时执行10 次,每次需要20000 个IO。我们先通过IO 消耗方面来分析。可以看出,两个Query 每小时所消耗的IO 总数目是一样的,都是 IO/小时。假设我们优化第一个Query,从20 个IO 降低到18 个IO,也就是仅仅降低了2 个IO,则我们节省了2 * 10000 = 20000 (IO/小时)。而如果希望通过优化第

9、二个Query 达到相同的效果,我们必须要让每个Query 减少20000 / 10 = 2000 IO。我想大家都会相信让第一个Query 节省2 个IO远比第二个Query 节省2000 个IO 来的容易。其次,如果通过CPU 方面消耗的比较,原理和上面的完全一样。只要让第一个Query 稍微节省一小块资源,就可以让整个系统节省出一大块资源,尤其是在排序,分组这些对CPU 消耗比较多的操作中尤其突出。最后,我们从对整个系统的影响来分析。一个频繁执行的高并发Query 的危险性比一个低并发的Query 要大很多。当一个低并发的Query 走错执行计划,所带来的影响主要只是该Query 的请求

10、者的体验会变差,对整体系统的影响并不会特别的突出,之少还属于可控范围。但是,如果我们一个高并发的Query 走错了执行计划,那所带来的后可很可能就是灾难性的,很多时候可能连自救的机会都不给你就会让整个系统Crash 掉。曾经我就遇到这样一案例,系统中一个并发度较高的Query 语句走错执行计划,系统顷刻间Crash,甚至我都还没有反应过来是怎么回事。当重新启动数据库提供服务后,系统负载立刻直线飙升,甚至都来不及登录数据库查看当时有哪些Active 的线程在执行哪些Query。如果是遇到一个并发并不太高的Query 走错执行计划,至少我们还可以控制整个系统不至于系统被直接压跨,甚至连问题根源都难

11、以抓到。定位优化对象的性能瓶颈当我们拿到一条需要优化的Query 之后,第一件事情是什么?是反问自己,这条Query 有什么问题?我为什么要优化他?只有明白了这些问题,我们才知道我们需要做什么,才能够找到问题的关键。而不能就只是觉得某个Query 好像有点慢,需要优化一下,然后就开始一个一个优化方法去轮番尝试。这样很可能整个优化过程会消耗大量的人力和时间成本,甚至可能到最后还是得不到一个好的优化结果。这就像看病一样,医生必须要清楚的知道我们病的根源才能对症下药。如果只是知道我们什么地方不舒服,然后就开始通过各种药物尝试治疗,那这样所带来的后果可能就非常严重了。所以,在拿到一条需要优化的Quer

12、y 之后,我们首先要判断出这个Query 的瓶颈到底是IO 还是CPU。到底是因为在数据访问消耗了太多的时间,还是在数据的运算(如分组排序等)方面花费了太多资源?一般来说,在MySQL 5.0 系列版本中,我们可以通过系统自带的PROFILING 功能很清楚的找出一个Query 的瓶颈所在。当然,如果读者朋友为了使用MySQL 的某些在5.1 版本中才有的新特性(如Partition,EVENT 等)亦或者是比较喜欢尝试新事务而早早使用的MySQL 5.1 的预发布版本,可能就没办法使用这个功能了,因为该功能在MySQL5.1 系列刚开始的版本中并不支持,不过让人非常兴奋的是该功能在最新出来的

13、MySQL 5.1 正式版(5.1.30)又已经提供了。而如果读者朋友正在使用的MySQL 是4.x 版本,那可能就只能通过自行分析Query 的各个执行步骤,找到性能损失最大的地方。明确的优化目标当我们定为到了一条Query 的性能瓶颈之后,就需要通过分析该Query 所完成的功能和Query 对系统的整体影响制订出一个明确的优化目标。没有一个明确的目标,优化过程将是一个漫无目的而且低效的过程,也很难达收到一个理想的效果。尤其是对于一些实现应用中较为重要功能点的Query 更是如此。如何设定优化目标?这可能是很多人都非常头疼的问题,对于我自己也一样。要设定一个合理的优化目标,不能过于理想也不

14、能放任自由,确实是一件非常头疼的事情。一般来说,我们首先需要清楚的了解数据库目前的整体状态,同时也要清楚的知道数据库中与该Query 相关的数据库对象的各种信息,而且还要了解该Query 在整个应用系统中所实现的功能。了解了数据库整体状态,我们就能知道数据库所能承受的最大压力,也就清楚了我们能够接受的最悲观情况。把握了该Query 相关数据库对象的信息,我们就应该知道实现该Query 的消耗最理想情况下需要消耗多少资源,最糟糕又需要消耗多少资源。最后,通过该Query 所实现的功能点在整个应用系统中的重要地位,我们可以大概的分析出该Query 可以占用的系统资源比例,而且我们也能够知道该Que

15、ry 的效率给客户带来的体验影响到底有多大。当我们清楚了这些信息之后,我们基本可以得出该Query 应该满足的一个性能范围是怎样的,这也就是我们的优化目标范围,然后就是通过寻找相应的优化手段来解决问题了。如果该Query 实现的应用系统功能比较重要,我们就必须让目标更偏向于理想值一些,即使在其他某些方面作出一些让步与牺牲,比如调整schema 设计,调整索引组成等,可能都是需要的。而如果该Query 所实现的是一些并不是太关键的功能,那我们可以让目标更偏向悲观值一些,而尽量保证其他更重要的Query 的性能。这种时候,即使需要调整商业需求,减少功能实现,也不得不应该作出让步。从Explain

16、入手现在,优化目标也已经明确了,自然是奥开始动手的时候了。我们的优化到底该从何处入手呢?答案只有一个,从Explain 开始入手。为什么?因为只有Explain 才能告诉你,这个Query 在数据库中是以一个什么样的执行计划来实现的。但是,有一点我们必须清楚,Explain 只是用来获取一个Query 在当前状态的数据库中的执行计划,在优化动手之前,我们比需要根据优化目标在自己头脑中有一个清晰的目标执行计划。只有这样,优化的目标才有意义。一个优秀的SQL 调优人员(或者成为SQL Performance Tuner),在优化任何一个SQL 语句之前,都应该在自己头脑中已经先有一个预定的执行计划

17、,然后通过不断的调整尝试,再借助Explain 来验证调整的结果是否满足自己预定的执行计划。对于不符合预期的执行计划需要不断分析Query 的写法和数据库对象的信息,继续调整尝试,直至得到预期的结果。当然,人无完人,并不一定每次自己预设的执行计划都肯定是最优的,在不断调整测试的过程中,如果发现MySQL Optimizer 所选择的执行计划的实际执行效果确实比自己预设的要好,我们当然还是应该选择使用MySQL optimizer 所生成的执行计划。上面的这个优化思路,只是给大家指了一个优化的基本方向,实际操作还需要不断的结合具体应用场景不断的测试实践来体会。当然也并不一定所有的情况都非要严格遵

18、循这样一个思路,规则是死的,人是活的,只有更合理的方法,没有最合理的规则。在了解了上面这些优化的基本思路之后,我们再来看看优化的几个基本原则。永远用小结果集驱动大的结果集很多人喜欢在优化SQL 的时候说用小表驱动大表,个人认为这样的说法不太严谨。为什么?因为大表经过WHERE 条件过滤之后所返回的结果集并不一定就比小表所返回的结果集大,可能反而更小。在这种情况下如果仍然采用小表驱动大表,就会得到相反的性能效果。其实这样的结果也非常容易理解,在MySQL 中的Join,只有Nested Loop 一种Join 方式,也就是MySQL 的Join 都是通过嵌套循环来实现的。驱动结果集越大,所需要循

19、环的此时就越多,那么被驱动表的访问次数自然也就越多,而每次访问被驱动表,即使需要的逻辑IO 很少,循环次数多了,总量自然也不可能很小,而且每次循环都不能避免的需要消耗CPU ,所以CPU 运算量也会跟着增加。所以,如果我们仅仅以表的大小来作为驱动表的判断依据,假若小表过滤后所剩下的结果集比大表多很多,结果就是需要的嵌套循环中带来更多的循环次数,反之,所需要的循环次数就会更少,总体IO 量和CPU 运算量也会少。而且,就算是非Nested Loop 的Join 算法,如Oracle 中的Hash Join,同样是小结果集驱动大的结果集是最优的选择。所以,在优化Join Query 的时候,最基本

20、的原则就是“小结果集驱动大结果集”,通过这个原则来减少嵌套循环中的循环次数,达到减少IO 总量以及CPU 运算的次数。尽可能在索引中完成排序只取出自己需要的Columns任何时候在Query 中都只取出自己需要的Columns,尤其是在需要排序的Query 中。为什么?对于任何Query,返回的数据都是需要通过网络数据包传回给客户端,如果取出的Column 越多,需要传输的数据量自然会越大,不论是从网络带宽方面考虑还是从网络传输的缓冲区来看,都是一个浪费。如果是需要排序的Query 来说,影响就更大了。在MySQL 中存在两种排序算法,一种是在MySQL4.1 之前的老算法,实现方式是先将需要

21、排序的字段和可以直接定位到相关行数据的指针信息取出,然后在我们所设定的排序区(通过参数sort_buffer_size 设定)中进行排序,完成排序之后再次通过行指针信息取出所需要的Columns,也就是说这种算法需要访问两次数据。第二种排序算法是从MySQL4.1 版本开始使用的改进算法,一次性将所需要的Columns 全部取出,在排序区中进行排序后直接将数据返回给请求客户端。改行算法只需要访问一次数据,减少了大量的随机IO,极大的提高了带有排序的Query 语句的效率。但是,这种改进后的排序算法需要一次性取出并缓存的数据比第一种算法要多很多,如果我们将并不需要的Columns 也取出来,就会

22、极大的浪费排序过程所需要的内存。在MySQL4.1 之后的版本中,我们可以通过设置max_length_for_sort_data 参数大小来控制MySQL 选择第一种排序算法还是第二种排序算法。当所取出的Columns 的单条记录总大小max_length_for_sort_data 设置的大小的时候,MySQL 就会选择使用第一种排序算法,反之,则会选择第二种优化后的算法。为了尽可能提高排序性能,我们自然是更希望使用第二种排序算法,所以在Query 中仅仅取出我们所需要的Columns 是非常有必要的。仅仅使用最有效的过滤条件很多人在优化Query 语句的时候很容易进入一个误区,那就是觉得

23、WHERE 子句中的过滤条件越多越好,实际上这并不是一个非常正确的选择。其实我们分析Query 语句的性能优劣最关键的就是要让他选择一条最佳的数据访问路径,如何做到通过访问最少的数据量完成自己的任务。为什么说过滤条件多不一定是好事呢?请看下面示例:需求: 查找某个用户在所有group 中所发的讨论message 基本信息。场景: 1、知道用户ID 和用户nick_name2、信息所在表为group_message3、group_message 中存在用户ID(user_id)和nick_name(author)两个索引方案一:将用户ID 和用户nick_name 两者都作为过滤条件放在WHER

24、E 子句中来查询,Query 的执行计划如下:skylocalhost : example 11:29:37 EXPLAIN SELECT * FROM group_message- WHERE user_id = 1 AND author=G* 1. row *id: 1select_type: SIMPLEtable: group_messagetype: refpossible_keys: group_message_author_ind,group_message_uid_indkey: group_message_author_indkey_len: 98ref: constrows

25、: 1Extra: Using where1 row in set (0.00 sec)方案二:仅仅将用户ID 作为过滤条件放在WHERE 子句中来查询,Query 的执行计划如下:skylocalhost : example 11:30:45 EXPLAIN SELECT * FROM group_message- WHERE user_id = 1G* 1. row *id: 1select_type: SIMPLEtable: group_messagetype: refpossible_keys: group_message_uid_indkey: group_message_uid_

26、indkey_len: 4ref: constrows: 1Extra:1 row in set (0.00 sec)方案三:仅将用户nick_name 作为过滤条件放在WHERE 子句中来查询,Query 的执行计划如下:skylocalhost : example 11:38:45 EXPLAIN SELECT * FROM group_message- WHERE author = G* 1. row *id: 1select_type: SIMPLEtable: group_messagetype: refpossible_keys: group_message_author_indk

27、ey: group_message_author_indkey_len: 98ref: constrows: 1Extra: Using where1 row in set (0.00 sec)初略一看三个执行计划好像都挺好的啊,每一个Query 的执行类型都利用到了索引,而且都是“ref”类型。可是仔细一分析,就会发现,group_message_uid_ind 索引的索引键长度为4(key_len:4),由于user_id 字段类型为int,所以我们可以判定出Query Optimizer 给出的这个索引键长度是完全准确的。而group_message_author_ind 索引的索引键长

28、度为98(key_len: 98),因为author 字段定义为varchar(32) ,而所使用的字符集是utf8,32 * 3 + 2 = 98。而且,由于user_id 与author(来源于nick_name)全部都是一一对应的,所以同一个user_id 有哪些记录,那么所对应的author 也会有完全相同的记录。所以,同样的数据在group_message_author_ind 索引中所占用的存储空间要远远大于group_message_uid_ind 索引所占用的空间。占用空间更大,代表我们访问该索引所需要读取的数据量就会更多。所以,选择group_message_uid_ind

29、的执行计划才是最有的执行计划。也就是说,上面的方案二才是最有方案,而使用了更多的WHERE 条件的方案一反而没有仅仅使用user_id一个过滤条件的方案一优。可能有些人会说,那如果将user_id 和author 两者建立联合索引呢?告诉你,效果可能比没有这个索引的时候更差,因为这个联合索引的索引键更长,索引占用的空间将会更大。这个示例并不一定能代表所有场景,仅仅是希望让大家明白,并不是任何时候都是使用的过滤条件越多性能会越好。在实际应用场景中,肯定会存在更多更复杂的情形,怎样使我们的Query 有一个更优化的执行计划,更高效的性能,还需要靠大家仔细分析各种执行计划的具体差别,才能选择出更优化

30、的Query。尽可能避免复杂的Join 和子查询我们都知道,MySQL 在并发这一块做的并不是太好,当并发量太高的时候,系统整体性能可能会急剧下降,尤其是遇到一些较为复杂的Query 的时候更是如此。这主要与MySQL 内部资源的争用锁定控制有关,如读写相斥等等。对于Innodb 存储引擎由于实现了行级锁定可能还要稍微好一些,如果使用的MyISAM 存储引擎,并发一旦较高的时候,性能下降非常明显。所以,我们的Query 语句所涉及到的表越多,所需要锁定的资源就越多。也就是说,越复杂的Join 语句,所需要锁定的资源就越多,所阻塞的其他线程也就越多。相反,如果我们将比较复杂的Query 语句分拆

31、成多个较为简单的Query 语句分步执行,每次锁定的资源也就会少很多,所阻塞的其他线程也要少一些。可能很多读者会有疑问,将复杂Join 语句分拆成多个简单的Query 语句之后,那不是我们的网络交互就会更多了吗?网络延时方面的总体消耗也就更大了啊,完成整个查询的时间不是反而更长了吗?是的,这种情况是可能存在,但也并不是肯定就会如此。我们可以再分析一下,一个复杂的Join Query语句在执行的时候,所需要锁定的资源比较多,可能被别人阻塞的概率也就更大,如果是一个简单的Query,由于需要锁定的资源较少,被阻塞的概率也会小很多。所以较为复杂的Join Query 也有可能在执行之前被阻塞而浪费更

32、多的时间。而且,我们的数据库所服务的并不是单单这一个Query 请求,还有很多很多其他的请求,在高并发的系统中,牺牲单个Query 的短暂响应时间而提高整体处理能力也是非常值得的。优化本身就是一门平衡与取舍的艺术,只有懂得取舍,平衡整体,才能让系统更优。对于子查询,可能不需要我多说很多人就明白为什么会不被推荐使用。在MySQL 中,子查询的实现目前还比较差,很难得到一个很好的执行计划,很多时候明明有索引可以利用,可Query Optimizer 就是不用。从MySQL 官方给出的信息说,这一问题将在MySQL6.0 中得到较好的解决,将会引入SemiJoin 的执行计划,可MySQL6.0 离

33、我们投入生产环境使用恐怕还有很遥远的一段时间。所以,在Query 优化的过程中,能不用子查询的时候就尽量不要使用子查询。上面这些仅仅只是一些常用的优化原则,并不是说在Query 优化中就只需要做到这些原则就可以,更不是说Query 优化只能通过这些原则来优化。在实际优化过程中,我们还可能会遇到很多带有较为复杂商业逻辑的场景,具体的优化方法就只能根据不同的应用场景来具体分析,逐步调整。其实,最有效的优化,就是不要用,也就是不要实现这个商业需求。充分利用Explain和ProfilingExplain 的使用说到Explain,肯定很多读者之前都都已经用过了,MySQL Query Optimiz

34、er 通过我让们执行EXPLAIN 命令来告诉我们他将使用一个什么样的执行计划来优化我们的Query。所以,可以说Explain是在优化Query 时最直接有效的验证我们想法的工具。在本章前面部分我就说过,一个好的SQL Performance Tuner 在动手优化一个Query 之前,头脑中就应该已经有一个好的执行计划,后面的优化工作只是为实现该执行计划而作出各种调整。在我们对某个Query 优化过程中,需要不断的使用Explain 来验证我们的各种调整是否有效。就像本书之前的很多示例都会通过Explain 来验证和展示结果一样,所有的Query 优化都应该充分利用他。我们先看一下在MyS

35、QL Explain 功能中给我们展示的各种信息的解释: ID:Query Optimizer 所选定的执行计划中查询的序列号; Select_type:所使用的查询类型,主要有以下这几种查询类型 DEPENDENT SUBQUERY:子查询中内层的第一个SELECT,依赖于外部查询的结果集; DEPENDENT UNION:子查询中的UNION,且为UNION 中从第二个SELECT 开始的后面所有SELECT,同样依赖于外部查询的结果集; PRIMARY:子查询中的最外层查询,注意并不是主键查询; SIMPLE:除子查询或者UNION 之外的其他查询; SUBQUERY:子查询内层查询的第

36、一个SELECT,结果不依赖于外部查询结果集; UNCACHEABLE SUBQUERY:结果集无法缓存的子查询; UNION:UNION 语句中第二个SELECT 开始的后面所有SELECT,第一个SELECT 为PRIMARY UNION RESULT:UNION 中的合并结果; Table:显示这一步所访问的数据库中的表的名称; Type:告诉我们对表所使用的访问方式,主要包含如下集中类型; all:全表扫描 const:读常量,且最多只会有一条记录匹配,由于是常量,所以实际上只需要读一次; eq_ref:最多只会有一条匹配结果,一般是通过主键或者唯一键索引来访问; fulltext:

37、index:全索引扫描; index_merge:查询中同时使用两个(或更多)索引,然后对索引结果进行merge 之后再读取表数据; index_subquery:子查询中的返回结果字段组合是一个索引(或索引组合),但不是一个主键或者唯一索引; rang:索引范围扫描; ref:Join 语句中被驱动表索引引用查询; ref_or_null:与ref 的唯一区别就是在使用索引引用查询之外再增加一个空值的查询; system:系统表,表中只有一行数据; unique_subquery:子查询中的返回结果字段组合是主键或者唯一约束; Possible_keys:该查询可以利用的索引. 如果没有任何

38、索引可以使用,就会显示成null,这一项内容对于优化时候索引的调整非常重要; Key:MySQL Query Optimizer 从possible_keys 中所选择使用的索引; Key_len:被选中使用索引的索引键长度; Ref:列出是通过常量(const),还是某个表的某个字段(如果是join)来过滤(通过key)的; Rows:MySQL Query Optimizer 通过系统收集到的统计信息估算出来的结果集记录条数; Extra:查询中每一步实现的额外细节信息,主要可能会是以下内容: Distinct:查找distinct 值,所以当mysql 找到了第一条匹配的结果后,将停止该

39、值的查询而转为后面其他值的查询; Full scan on NULL key:子查询中的一种优化方式,主要在遇到无法通过索引访问null值的使用使用; Impossible WHERE noticed after reading const tables:MySQL Query Optimizer 通过收集到的统计信息判断出不可能存在结果; No tables:Query 语句中使用FROM DUAL 或者不包含任何FROM 子句; Not exists:在某些左连接中MySQL Query Optimizer 所通过改变原有Query 的组成而使用的优化方法,可以部分减少数据访问次数; Ra

40、nge checked for each record (index map: N):通过MySQL 官方手册的描述,当MySQL Query Optimizer 没有发现好的可以使用的索引的时候,如果发现如果来自前面的表的列值已知,可能部分索引可以使用。对前面的表的每个行组合,MySQL 检查是否可以使用range 或index_merge 访问方法来索取行。 Select tables optimized away:当我们使用某些聚合函数来访问存在索引的某个字段的时候,MySQL Query Optimizer 会通过索引而直接一次定位到所需的数据行完成整个查询。当然,前提是在Query

41、中不能有GROUP BY 操作。如使用MIN()或者MAX()的时候; Using filesort:当我们的Query 中包含ORDER BY 操作,而且无法利用索引完成排序操作的时候,MySQL Query Optimizer 不得不选择相应的排序算法来实现。 Using index:所需要的数据只需要在Index 即可全部获得而不需要再到表中取数据; Using index for group-by:数据访问和Using index 一样,所需数据只需要读取索引即可,而当Query 中使用了GROUP BY 或者DISTINCT 子句的时候,如果分组字段也在索引中,Extra 中的信息就

42、会是Using index for group-by; Using temporary:当MySQL 在某些操作中必须使用临时表的时候,在Extra 信息中就会出现Using temporary 。主要常见于GROUP BY 和ORDER BY 等操作中。 Using where:如果我们不是读取表的所有数据,或者不是仅仅通过索引就可以获取所有需要的数据,则会出现Using where 信息; Using where with pushed condition:这是一个仅仅在NDBCluster 存储引擎中才会出现的信息,而且还需要通过打开Condition Pushdown 优化功能才可能会

43、被使用。控制参数为engine_condition_pushdown 。这里我们通过分析示例来看一下不同的Query 语句通过Explain 所显示的不同信息:我们先看一个简单的单表Query:skylocalhost : example 11:33:18 explain select count(*),max(id),min(id)- from userG* 1. row *id: 1select_type: SIMPLEtable: NULLtype: NULLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLExtra

44、: Select tables optimized away对user 表的单表查询,查询类型为SIMPLE,因为既没有UNION 也不是子查询。聚合函数MAX MIN以及COUNT 三者所需要的数据都可以通过索引就能够直接定位得到数据,所以整个实现的Extra 信息为Select tables optimized away。再来看一个稍微复杂一点的Query,一个子查询:skylocalhost : example 11:38:48 explain select name from groups- where id in ( select group_id from user_group w

45、here user_id = 1)G* 1. row *id: 1select_type: PRIMARYtable: groupstype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 50000Extra: Using where* 2. row *id: 2select_type: DEPENDENT SUBQUERYtable: user_grouptype: refpossible_keys: user_group_gid_ind,user_group_uid_indkey: user_group_uid_in

46、dkey_len: 4ref: constrows: 1Extra: Using where通过id 信息我们可以得知MySQL Query Optimizer 给出的执行计划是首先对groups 进行全表扫描,然后第二步才访问user_group 表,所使用的查询方式是DEPENDENT SUBQUERY,对所需数据的访问方式是索引扫描,由于过滤条件是一个整数,所以索引扫描的类型为ref,过滤条件是const。可以使用的索引有两个,一个是基于user_id,另一个则是基于group_id 的。为什么基于group_id 的索引user_group_gid_ind 也被列为可选索引了呢?是因为与子查询的外层查询所关联的条件是基于group_id 的。当然,最后MySQL Query Optimizer 还是选择了使用基于user_id 的索引user_group_uid_ind。Profiling 的使用在前面我们还提到过通过Query Profiler 来定位一条Query 的性能瓶颈,这里我们再详细介绍一下Profiling 的用途及使用方法。要想优化一条Query,我们就需要清楚的知道这条Query 的性能瓶颈到底在哪里,是消耗的CPU计算太多,还是需要

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 教案示例

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com