MYSQL Server 如何工做

1客户端发送一条查询给服务器;
2服务器会先检查查询缓存,若是命中了缓存,则当即返回存储在缓存中的结果。不然进入下一阶段;
3服务器端进行SQL解析、预处理、再由优化器生成对应的执行计划;
4MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询;
5将结果返回客户端。数据库

查询缓存 (query cahche)

在解析一个查询语句以前,若是查询缓存是打开的,那么MySQL会优先检查这个查询是否命中查询缓存中的数据。这个检查是经过一个对大小写敏感的哈希查找实现的。查询和缓存中的查询即便只有一个字节不一样,那也不会匹配缓存结果,这种状况查询会进入下一个阶段的处理。缓存

若是当前的查询刚好命中了查询缓存,那么在返回查询结果以前MySQL会检查一次用户权限。这仍然是无须解析查询SQL语句的,由于在查询缓存中已经存放了当前查询须要访问的表信息。若是权限没有问题,MySQL会跳过全部其余阶段,直接从缓存中拿到结果并返回给客户端。这种状况下,查询不会被解析,不用生成执行计划,不会被执行。服务器

缓存配置参数:数据结构

query_cache_limit: MySQL可以缓存的最大结果,若是超出,则增长 Qcache_not_cached的值,并删除查询结果并发

query_cache_min_res_unit: 分配内存块时的最小单位大小函数

query_cache_size: 缓存使用的总内存空间大小,单位是字节,这个值必须是1024的整数倍,不然MySQL实际分配可能跟这个数值不一样(感受这个应该跟文件系统的blcok大小有关)优化

query_cache_type: 是否打开缓存 OFF: 关闭 ON: 老是打开spa

query_cache_wlock_invalidate: 若是某个数据表被锁住,是否仍然从缓存中返回数据,默认是OFF,表示仍然能够返回3d

语法解析器和预处理器

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

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

下一步预处理器会验证权限,这一般很快,除非服务器上有很是多的权限设置。

查询优化器

如今语法树被认为合法的了,而且由优化器将其转化为执行计划。一条查询能够由不少种执行方式,最后都返回相同的结果。优化器的做用就是找到这其中最好的执行计划。

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

有不少种缘由会致使MySQL优化器选择错误的执行计划,好比:

1. 统计信息不许确。

2. 执行计划中的成本估算不等同于实际的执行计划的成本。

3. MySQL的最优可能与你想的最优不同。

4. MySQL从不考虑其余并发的查询,这可能会影响当前查询的速度。

5. MySQL也不是任什么时候候都是基于成本的优化,有时候也会基于一些固定的规则。

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

MySQL的查询优化使用了不少优化策略来生成一个最优的执行的计划。优化策略能够分为两种,静态优化和动态优化。静态优化能够直接对解析树进行分析,并完成优化。例如优化器能够经过一些简单的代数变换将where条件转换成另外一种等价形式。静态优化不依赖于特别的数值,如where条件中带入的一些常数等。静态优化在第一次完成后就一直有效,即便使用不一样的参数重复查询也不会变化,能够认为是一种“编译时优化”。

相反,动态优化则和查询的上下文有关。也可能和不少其余因素有关,例如where条件中的取值、索引中条目对应的数据行数等,这些须要每次查询的时候从新评估,能够认为是“运行时优化”。

下面是一些MySQL可以处理的优化类型:

1. 从新定义关联表的顺序

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

2. 将外链接转化成内链接

并非全部的outer join语句都必须之外链接的方式执行。诸多因素,例如where条件、库表结构均可能会让外链接等价于一个内链接。MySQL可以识别这点并重写查询,让其能够调整关联顺序。

3. 使用等价变换规则

MySQL可使用一些等价变换来简化并规范表达式。它能够合并和减小一些比较,还能够移除一些恒成立和一些恒不成立的判断。例如:(5=5 and a>5)将被改写为a>5。相似的,若是有(a<b and b=c)and a=5,则会被改写为 b>5 and b=c and a=5。

4. 优化count()、min()和max()

索引和列是否为空一般能够帮助MySQL优化这类表达式。例如,要找到一列的最小值,只须要查询对应B-tree索引最左端的记录,MySQL能够直接获取索引的第一行记录。在优化器生成执行计划的时候就能够利用这一点,在B-tree索引中,优化器会讲这个表达式最为一个常数对待。相似的,若是要查找一个最大值,也只须要读取B-tree索引的最后一个记录。若是MySQL使用了这种类型的优化,那么在explain中就能够看到“select tables optimized away”。从字面意思能够看出,它表示优化器已经从执行计划中移除了该表,并以一个常数取而代之。

相似的,没有任何where条件的count(*)查询一般也可使用存储引擎提供的一些优化,例如,MyISAM维护了一个变量来存放数据表的行数。

5. 预估并转化为常数表达式

6. 覆盖索引扫描

当索引中的列包含全部查询中须要使用的列的时候,MySQL就可使用索引返回须要的数据,而无需查询对应的数据行。

7. 子查询优化

MySQL在某些状况下能够将子查询转换成一种效率更高的形式,从而减小多个查询屡次对数据进行访问。

8. 提早终止查询

在发现已经知足查询需求的时候,MySQL老是可以当即终止查询。一个典型的例子就是当使用了limit子句的时候。除此以外,MySQL还有几种状况也会提早终止查询,例如发现了一个不成立的条件,这时MySQL能够当即返回一个空结果。

9. 等值传播

10. 列表in()的比较

在不少数据库系统中,in()彻底等同于多个or条件的字句,由于这二者是彻底等价的。在MySQL中这点是不成立的,MySQL将in()列表中的数据先进行排序,而后经过二分查找的方式来肯定列表中的值是否知足条件,这是一个o(log n)复杂度的操做,等价转换成or的查询的复杂度为o(n),对于in()列表中有大量取值的时候,MySQL的处理速度会更快。

查询执行引擎

在解析和优化阶段,MySQL将生成查询对应的执行计划,MySQL的查询执行引擎则根据这个执行计划来完成整个查询。这里执行计划是一个数据结构,而不是和不少其余的关系型数据库那样会生成对应的字节码。

相对于查询优化阶段,查询执行阶段不是那么复杂:MySQL只是简单的根据执行计划给出的指令逐步执行。在根据执行计划逐步执行的过程当中,有大量的操做须要经过调用存储引擎实现的接口来完成,这些接口就是咱们称为“handler API”的接口。实际上,MySQL在优化阶段就为每一个表建立了一个handler实例,优化器根据这些实例的接口能够获取表的相关信息,包括表的全部列名、索引统计信息等。

返回结果给客户端

查询执行的最后一个阶段是将结果返回给客户端。即便查询不须要返回结果给客户端,MySQL仍然会返回这个查询的一些信息,如查询影响到的行数。

若是查询能够被缓存,那么MySQL在这个阶段,会将结果存放到查询缓存中。

MySQL将结果返回客户端是一个增量、逐步返回的过程。例如,在关联表操做时,一旦服务器处理完最后一个关联表,开始生成第一条结果时,MySQL就能够开始向客户端逐步返回结果集了。

这样处理有两个好处:服务器无需存储太多的结果,也就不会由于要返回太多的结果而消耗太多的内存。另外,这样的处理也让MySQL客户端第一时间得到返回的结果。

结果集中的每一行都会以一个知足MySQL客户端/服务器通讯协议的封包发送,再经过TCP协议进行传输,在TCP传输过程当中,可能对MySQL的封包进行缓存而后批量传输。

相关文章
相关标签/搜索