MySQL查询优化处理

  查询的生命周期的下一步是将一个sql转化成一个执行计划,MySQL再依照这个执行计划和存储引擎进行交互。这包括多个子阶段:解析sql,预处理,优化sql执行计划。这个过程中任何错误(例如语法错误)都可能终止查询。这里不打算详细介绍MySQL内部实现,而只是选择性的介绍其中几个独立的部分,在实际中,这几部分可能以前执行也可能单独执行。我们的目的是帮助大家理解MySQL是如何执行查询的,以便写出更优秀的查询。

·  语法解析器和预处理

  首先,MySQL通过关键字语句进行解析,并生成一科对应的“解析树”,MySQL集线器将使用MySQL语法规则验证和解析查询。例如,它将验证是否使用错误的关键字,或者使用关键字的顺序是不是正确等,再或者他还会验证引号是否能前后正确匹配。  

  预处理器则根据一些MySQL规则进一步验证解析树是否合法,,例如,这里将坚持数据表和数据列是否存在,还会解析名字和别名,看看他们是否有歧义。

  下一步预处理器会验证权限。这通常会非常快,除非服务器上有非常多的权限配置。

  查询优化器

  限制语法数被认为是合法的了,并且由优化器将其转化成执行计划。一条查询可以有很多种查询方式,最后都会返回相同的结果。游虎丘的作用就是找到这其中最好的执行计划。

  MySQL使用基于成本的优化器,它将尝试预测一个查询使用某种执行计划时的成本,并选择其中成本最小的一个。最初,成本的最小单位是随机读取一个4k的数据源的成本,后来(成本的计算公式)变得更加复杂,并且引入了一些“因子”来估算某些操作的代价,如当执行一次where条件比较的成本。可以通过查询当前会话的Last_query_cost的值来的值MySQL计算的当前查询的成本。

  SELECT SQL_NO_CACHE COUNT(*) FROM actor;

  SELECT STATUS LIKE ‘Last_query_cost‘

  Variable_name  Value

  Last_query_cost  1040.343400

这个结果表示MySQL的优化器认为大概需要做1040个数据源的随机查找才能完成上面的查询。这是根据一系列的统计信息计算得来的:每个表或者索引的页面个数、索引的基数(索引中不同值的数量)、索引和数据行的长度、索引的分布情况。优化器在评估成本的时候并不会考虑任何层面的缓冲,它假设读取任何数据都需要一次磁盘io

  很多原因会导致MySQL优化器选择错误的执行计划,如下所示:

  统计信息不准确。MySQL依赖存储引擎提供的统计信息来评估成本,但是有的存储引擎提供的信息是准确的,优点偏差可能非常大。例如,innodb因为其mvcc的架构,并不能维护一个数据表的行数的精确的统计信息。

  执行计划中的成本估算不等同于实际执行的成本。所以即使统计信息准确,优化器给出的执行计划也可能不是罪优的。例如有时候某个执行计划虽然需要读取更多的页面,但是他的成本却更小。因为如果这些页面都是顺序读取或者这些页面都已经在内存中存在,那么它的访问成本将会很小。MySQL层面并只知道那些页面在内存中,那些在磁盘上,所以查询实际执行的过冲中到底需要多少次窝里io是无法得知的。

  MySQL的最优化可能和你像的最后不一样。你可能希望执行时间尽可能的短,但是MySQL只是基于其成本模型选择最优的执行计划,而有些时候这并不是最快的执行方式。索引,这里我们看到的根据执行成本来选择执行计划并不是完美的模型。

  MySQL从不考虑其他并发的执行查询,这可能会影响到当前的查询速度。

  MySQL也并不是任何时候都是基于成本的优化。有时也会基于一些固定的规则,例如,如果在全文所搜的MATCH()子句,则在全文索引的时候就使用全文索引,即使有时候使用别的索引和where条件可以远比这方式要快,MySQL仍然会使用对应的全文索引。

  MySQL不会考虑其控制的操作成本,例如执行存储过程或者用户自定义函数的成本。

  后面我们还会看到,优化器有时候无法去估算所有可能的执行计划,所以它可能错过实际上最优的执行计划。

  MySQL的查询优化器是一个非常复杂的部件,它使用了很多优化策略来生成一个最优的执行计划。优化策略可以简单的分为两种:一种是静态优化,一种是动态优化。静态优化可以直接对解析树进行分析,并完成优化。例如,又好看可以通过一些简单的代数变化将WHERE 条件转换成另一种等价的形式。静态优化不依赖于特别的数值,如where条件中带入的一些常数等。静态优化在第一次完成后就一直有效,即使使用不同的参数执行查询也不会发生变化。可以认为这是一种“编译时优化”。

  相反,动态优化则和查询的上下文有关,也可能和很多其他因素有关,例如WHERE 条件中的取值,索引中那个条目对应的数据行数等。这需要在每次查询的时候都重新评估,可以认为这是 “运行时优化”。

  在执行语句和存储过程的时候,动态优化和静态优化的区别非常重要。MySQL对查询的静态优化只需要做一次,但对查询的动态优化规则在每次执行的时候都需要评估,有时候甚至在查询的过程中重新优化(例如,在关联操作过程中,范围检查的执行计划会针对每一行重新评估索引。可以通过EXPLAIN 执行计划红的Extra列是否有“range checked for each record” 来确认这一点。该执行计划还会增加select_full_range_join 这个服务器变量的值)。

  下面是MySQL能够处理的优化类型:

  重新定义关联表的顺序

  数据表的关联并不总是按照在查询中指定的顺序进行。决定关联的顺序是优化器很重要的一部分功能。

  将外连接转化成内连接

  并不是所有的OUTER JOIN 语句都必须以外连接的方式执行。诸多因素,例如WHERE 条件,库表结构都可能会让外连接等价成一个内连接。MySQL能够识别这点,并重写查询,让其可以调整关联顺序。

  使用等价变换规则

  MySQL可以使用一些等价变换来简化并规范表达式。它可以合并和减少一些比较,还可以移除一些恒成立和一些恒不成立的判断。例如(5=5 and a>5) 将被改写成a>5 .类似的,如果有(a<b AND b<c) AND a = 5则会改写成b>5 AND b=c AND a=5。这些条件对于我们编写条件语句很有用。

  优化COUNT () ,MIN()和MAX()

  索引和列是否可为空通常可以帮助MySQL优化这类表达式。例如,要找到某一列的最小值,只需要查询在B-Tree索引最左短的记录,MySQL可以直接获取索引一行记录。在优化器生成执行计划的时候就可以利用这一点,在B-Tree 索引中,优化器会将这个表达式作为一个常数对待。类似的,如果要查找一个最大值,也只需要读取b-tree所用的最后一条记录。如果MySQL使用了这种类型的优化,那么再EXLAIN中就可以看到’Select tables optimized away‘ 。从字面的意思可以看出,他表示优化器已经冲执行计划中移除了该表,并以一个常数取而代之。

  

  

时间: 2025-01-10 23:46:23

MySQL查询优化处理的相关文章

Mysql查询优化器浅析

--Mysql查询优化器浅析 -----------------------------2014/06/11 1 定义 Mysql查询优化器的工作是为查询语句选择合适的执行路径.查询优化器的代码一般是经常变动的,这和存储引擎不太一样.因此,需要理解最新版本的查询优化器是如何组织的,请参考相应的源代码.整体而言,优化器有很多相同性,对mysql一个版本的优化器做到整体掌握,理解起mysql新版本以及其他数据库的优化器都是类似的. 优化器会对查询语句进行转化,转化等价的查询语句.举个例子,优化器会将

MySQL查询优化之explain的深入解析

MySQL查询优化之explain的深入解析 作者: 字体:[增加 减小] 类型:转载 时间:2013-06-13我要评论 本篇文章是对MySQL查询优化中的explain进行了详细的分析介绍,需要的朋友参考下 在分析查询性能时,考虑EXPLAIN关键字同样很管用.EXPLAIN关键字一般放在SELECT查询语句的前面,用于描述MySQL如何执行查询操作.以及MySQL成功返回结果集需要执行的行数.explain 可以帮助我们分析 select 语句,让我们知道查询效率低下的原因,从而改进我们查

Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析

    Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析1 存取类型1 5         范围存取类型2 6         索引存取类型2 7         转换3 AND3 9         OR3 10    UNION3 11    NOT,<>4 12    ORDER BY4 13    GROUP BY4 存取类型 当我们评估一个条件表达式,MySQL判断该表达式的存取类型.下面是一些存取类型,按照从最优到最差的顺序进行排列: s

Mysql查询优化器

本文的目的主要是通过告诉大家,查询优化器为我们做了那些工作,我们怎么做,才能使查询优化器对我们的sql进行优化,以及启示我们sql语句怎么写,才能更有效率.那么到底mysql到底能进行哪些优化那,下面通过以下几个方面来探讨一下: 1.常量转化 它能够对sql语句中的常量进行转化,比如下面的表达式: WHERE col1 = col2 AND col2 = 'x'; 依据传递性:如果A=B and B=C,那么就能得出A=C.所以上面的表达式mysql查询优化器能进行如下的优化:WHERE col

MySql查询优化方法总结

常用查询优化 1: max()优化: 在相应列上添加索引2: count()优化:count(*) 会算出包含null记录的数量, count(field_name)只包含不含 null的数量(这也是很多时候两种count方式结果不一致的原因), count()的时候尽量用后一种, count(null)返回0,即不会记录null记录数量3: 子查询优化=====>(改为)联接查询(如果1对多的关系,注意重复记录)4: group by优化 如果包含子查询,在子查询里面使用where条件和gro

MySql查询优化limit 1避免全表扫描(转)

在某些情况下,如果明知道查询结果只有一个,SQL语句中使用LIMIT 1会提高查询效率. 例如下面的用户表(主键id,邮箱,密码): create table t_user(id int primary key auto_increment,email varchar(255),password varchar(255)); 每个用户的email是唯一的,如果用户使用email作为用户名登陆的话,就需要查询出email对应的一条记录. SELECT * FROM t_user WHERE ema

1025WHERE执行顺序以及MySQL查询优化器

转自http://blog.csdn.net/zhanyan_x/article/details/25294539 -- WHERE执行顺序-- 过滤比较多的放在前面,然后更加容易匹配,从左到右进行执行:一般都是优化器很智能的优化了,无需用户处理-- 如何查看优化后的语句EXPLAIN EXTENDEDSELECT SQL_NO_CACHE * FROM db.tableWHERE is_day=1 AND DATE(ex_date)='2015-07-01' ; SHOW WARNINGS;

MYSQL查询优化(Ⅱ)

本文列举出五个MySQL查询优化的方法,当然,优化的方法还有很多. 1.优化数据类型 MySQL中数据类型有多种,如果你是一名DBA,正在按照优化的原则对数据类型进行严格的检查,但开发人员可能会选择他们认为最简单的方案,以加快编码速度,或者选择最明显的选择,因此,你可能面临的都不是最佳的选择,如果可能的话,你应该尝试以通用准则来改变这些决定. (1)避免使用NULL NULL对于大多数数据库都需要特殊处理,MySQL也不例外,它需要更多的代码,更多的检查和特殊的索引逻辑,有些开发人员完全没有意识

010 --MySQL查询优化器的局限性

MySQL的万能"嵌套循环"并不是对每种查询都是最优的.不过还好,mysql查询优化器只对少部分查询不适用,而且我们往往可以通过改写查询让mysql高效的完成工作.在这我们先来看看mysql优化器有哪些局限性: 1.关联子查询 mysql的子查询实现得非常糟糕.最糟糕得一类查询是where条件中包含in()的子查询语句.例如,我们希望找到sakila数据库中,演员Penlope Guiness参演的所有影片信息.很自然的,我们会按照下面的方式用子查询实现: select * from

结合mysql查询优化器对联合索引的探讨

无陈述,直接开讲: babysitter_account表中的联合索引如下(开发小伙伴们自建的联合索引.您发现不妥了吗?): KEY `flag` (`flag`,`user_id`,`account_id`) 过去认为: 1.SELECT account_id,weibo_id,weibo_type FROM babysitter_account WHERE user_id BETWEEN 100 and 10000 AND flag=0; 2.SELECT account_id,weibo_