首先先简略的将一个查问语句背地 MySQL 做了什么捋一捋:
- 客户端发送一条查问给服务器。
- 服务器先查看查问缓存,如果命中了缓存,则立即返回存储在缓存中的后果。否则进入下一个阶段。
- 服务器端进行 SQL 解析,预处理,再由优化器生成对应的执行打算。
- MySQL 依据优化器生成的执行打算,调用存储引擎的 API 来执行查问。
- 将后果返回给客户端。
接着咱们就将这个过程中的这些步骤具体的进行开展。
1. 客户端和服务器端之间的通信形式
客户端和服务器之间的通信是一种半双工的通信,即在同一时刻,只能有一方向另一方发送数据。所以客户端在发送完查问申请之后,所能做的就是期待服务器将查问的后果返回,并且须要始终地等到返回的数据全副接管结束后能力进行下一步的操作,而不能够在服务器发送的过程中中断发送或者断开连接。
2. 查问缓存
在解析一个查问语句之前,如果查问缓存是关上着的,那么 MySQL 会优先查看这个查问是否命中查问缓存中的数据。这个查看是通过一个对大小写敏感的哈希表来实现的。在查问命中缓存的状况下,间接从缓存中拿到后果并返回给客户端。MySQL 不会再执行上面的操作,即查问语句不会被解析,不会生成执行打算,不会被执行。
3. 查问优化解决
这个环节可能是整个查问执行过程中最为简单的一个环节,能够分为解析 SQL,预处理和优化 SQL 执行打算三个步骤。
(1)语法解析器和预处理
这个过程就是对咱们传入的 SQL 语句的语法进行查看,以及验证查问的权限。炳辉生成一棵“解析树”。
(2)查问优化器
在进入到这一步时,证实咱们的语句语法层面曾经没有问题了。一条查问能够有很多种执行打算都能返回正确的后果,这个环节就是来选取最优的执行打算的。
MySQL 的最优执行打算是基于老本的。MySQL 会为每个操作设定一个老本(如执行一次 where 比拟),并从所有的执行打算中抉择“老本”起码的。
咱们能够应用下列语句查看上一个查问操作的老本:
mysql> SHOW STATUS LIKE 'last_query_cost';
MySQL 会返回一个执行的老本数据:
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| Last_query_cost | 0.549000 |
+-----------------+----------+
但值得注意的是,这里的“老本”最小并不等于查问的速度最快。即以“老本”来判断查问语句的优劣有时候是不牢靠的。
优化器的优化策略能够大抵地分为两种:动态优化 和动静优化。
动态优化 是间接对之前生成的解析树进行剖析,例如能够通过一些代数变换将 where 条件转化为另一种等价模式。动态优化在第一次实现后就始终失效,即便应用不同的参数反复执行查问也不会发生变化,能够认为是一种“编译(预处理)时优化”。
动静优化 和查问的上下文相干,须要在每一次查问的时候从新评估,能够认为是一种“运行时优化”。
上面是一些 MySQL 可能解决的优化类型:
- 从新定义关联表的程序
有时候咱们所给的查问语句关联表的程序可能对于查问来说效率并不是最优的,这时候 MySQL 能够主动帮咱们将关联表的程序进行调整提高效率。
- 将外连贯转化为内连贯
并不是所有的 OUT JOIN 语句都必须以外连贯的形式执行。MySQL 可能辨认这一点并重写查问,让其能够调整关联程序。
- 应用等价变换规定
应用一些等价的语句来缩小比拟的次数,移除一些恒成立和不恒成立的条件。例如,(5=5 AND a>5)会被改写为 a >5; 如果有(a5 AND b=c AND a=5。
- 优化 COUNT()、MIN()和 MAX()
索引和列是否为空能够帮忙优化这一类表达式。例如查找最小值的时候就能够借助索引间接查找最左端的记录,这样就不必进行整个表的查问,而是以一个常数进行取代。
- 笼罩索引扫描
当索引中的列蕴含所有查问中须要应用的列的时候,MySQL 就会应用索引返回所须要的数据,而无须查问对应的数据行。
- 提前终止查问
在发现查问曾经能满足需要的时候,MySQL 总能立即终止查问。一个典型的例子就是当应用了 LIMIT 子句的时候。
至此,MySQL 服务器层曾经依据所给的查问语句给出了一个最优的执行打算。然而咱们须要晓得的是,咱们到目前为止所进行的一些列的操作都是在服务器层进行的,而这一层中并不是数据存储的中央。因而接下来咱们须要拿着咱们的最优执行打算去到理论的存储引擎中进行查找。因而就引出了咱们的下一步操作:向存储引擎获取相应的统计信息。
4. 查问执行引擎
绝对于查问优化阶段,查问执行阶段并不是那么简单。MySQL 只是简略地依据执行打算给出的指令逐渐执行。
5. 返回后果给客户端
查问执行的最初一个阶段是将后果返回给客户端,即便查问不须要返回后果集给客户端,MySQL 依然会返回这个查问的一些信息,例如查问影响的行数。
如果查问能够被缓存,这个阶段 MySQL 会讲查问的后果放到查问缓存中。
返回后果的过程是一个逐渐增量的过程。即当拿到第一个后果的时候就开始向客户端返回了。这样做的益处是不会一次性返回全副数据导致占用内存过多,而且客户端也能在第一工夫拿到后果。后果集中的每一行都会以一个满足 MySQL 客户端 / 服务器通信协议的封包发送,再通过 TCP 协定进行传输,在 TCP 传输的过程中,可能对封包进行缓存后再批量发传输。