MySQL查询步骤及优化

过程概览

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

查询缓存

在解析一个查询语句之前,如果查询缓存是打开的,那么MySQL会优先检查这个查询是否命中查询缓存中的数据。这个检查是通过一个对大小写敏感的哈希查找实现的。查询和缓存中的查询即使只有一个字节不同,那也不会匹配缓存结果,这种情况查询会进入下一个阶段的处理。
如果当前的查询恰好命中了查询缓存,那么在返回查询结果之前MySQL会检查一次用户权限。这仍然是无须解析查询SQL语句的,因为在查询缓存中已经存放了当前查询需要访问的表信息。如果权限没有问题,MySQL会跳过所有其他阶段,直接从缓存中拿到结果并返回给客户端。这种情况下,查询不会被解析,不用生成执行计划,不会被执行。
缓存配置参数:

MySQL查询步骤及优化_第1张图片
image.png

query_cache_limit: MySQL能够缓存的最大结果,如果超出,则增加qcache_not_cached的值,并删除查询结果
query_cache_min_res_unit: 分配内存块时的最小单位大小
query_cache_size: 缓存使用的总内存空间大小,单位是字节,这个值必须是1024的整数倍,否则MySQL实际分配可能跟这个数值不同(感觉这个应该跟文件系统的blcok大小有关)
query_cache_type: 是否打开缓存 OFF: 关闭,ON: 总是打开
query_cache_wlock_invalidate: 如果某个数据表被锁住,是否仍然从缓存中返回数据,默认是OFF,表示仍然可以返回。

查询管理器

在缓存中没有命中到,则进入MySQL语句的查询管理器中进行处理。
在这里查询语句可以转换成一个快速执行的代码,代码执行的结果被送到客户端管理器。这个多步骤操作过程如下

  1. 查询首先被解析并判断是否合法
  2. 然后被重写,去除了无用的操作并且加入预优化部分
  3. 然后被重写,去除了无用的操作并且加入预优化部分
  4. 接着被优化以便提升性能,并被转换为可执行代码和数据访问计划。
  5. 然后计划被编译
  6. 最后,被执行

这个过程涉及到如下几个组成器件:
查询解析器(Query parser):用于检查查询是否合法
查询重写器(Query rewriter):用于预优化查询
查询优化器(Query optimizer):用于优化查询
查询执行器(Query executor):用于编译和执行查询

语法解析器

首先,MySQL通过关键字将SQL语句进行解析,并生成一棵对应的“解析树”。MySQL解析器将使用MySQL语法规则验证和解析查询。例如,它将验证是否使用错误的关键字,或者使用关键字的顺序是否正确等,再或者它还会验证引号是否能前后正确的匹配。如果查询有错,解析器将拒绝该查询。比如,如果你写成”SLECT …” 而不是 “SELECT …”,那就没有下文了。

解析器还会检查关键字是否使用正确的顺序,比如 WHERE 写在 SELECT 之前会被拒绝。
然后,解析器要分析查询中的表和字段,使用数据库元数据来检查:

  • 表是否存在
  • 表的字段是否存在
  • 对某类型字段的 运算 是否 可能(比如,你不能将整数和字符串进行比较,你不能对一个整数使用 substring() 函数)

接着,解析器检查在查询中你是否有权限来读取(或写入)表。强调一下:这些权限由DBA分配。

查询重写器

在这一步,我们已经有了查询的内部表示,重写器的目标是:

  1. 预优化查询
  2. 避免不必要的运算
  3. 帮助优化器找到合理的最佳解决方案

重写器按照一系列已知的规则对查询执行检测。如果查询匹配一种模式的规则,查询就会按照这条规则来重写。下面是(可选)规则的非详尽的列表:

  1. 视图合并:如果你在查询中使用视图,视图就会转换为它的 SQL 代码。
  2. 子查询扁平化:子查询是很难优化的,因此重写器会尝试移除子查询
  3. 去除不必要的运算符:比如,如果你用了 DISTINCT,而其实你有 UNIQUE 约束(这本身就防止了数据出现重复),那么 DISTINCT 关键字就被去掉了。
  4. 排除冗余的联接:如果相同的 JOIN 条件出现两次,比如隐藏在视图中的 JOIN 条件,或者由于传递性产生的无用 JOIN,都会被消除。
  5. 常数计算赋值:如果你的查询需要计算,那么在重写过程中计算会执行一次。比如 WHERE AGE > 10+2 会转换为 WHERE AGE > 12 , TODATE(“日期字符串”) 会转换为 datetime 格式的日期值。
  6. (高级)分区裁剪(Partition Pruning):如果你用了分区表,重写器能够找到需要使用的分区。
  7. (高级)物化视图重写(Materialized view rewrite):如果你有个物化视图匹配查询谓词的一个子集,重写器将检查视图是否最新并修改查询,令查询使用物化视图而不是原始表。
  8. (高级)自定义规则:如果你有自定义规则来修改查询(就像 Oracle policy),重写器就会执行这些规则。
  9. (高级)OLAP转换:分析/加窗 函数,星形联接,ROLLUP 函数……都会发生转换(但我不确定这是由重写器还是优化器来完成,因为两个进程联系很紧,必须看是什么数据库)。
    重写后的查询接着送到优化器。

查询优化器

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

MySQL使用的是“选取-投影-联接”策略进行查询。用一个例子就可以理解: select uid,name from user where gender = 1;

  1. 这个select 查询先根据where 语句进行选取,而不是先将表全部查询出来以后再进行gender过滤
  2. 这个select查询先根据uid和name进行属性投影,而不是将属性全部取出以后再进行过滤
  3. 将这两个查询条件联接起来生成最终查询结果.

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

问题

  1. 缓存是内存还是硬盘(内存中)
  2. select->update->select时候,update如何通知缓存(发生更改,缓存立刻失效,写入会导致缓存频繁失效,降低效率)

资料

MySQL查询语句执行的过程
MySQL性能优化——易实现的MySQL优化方案汇总
MySQL优化原理

你可能感兴趣的:(MySQL查询步骤及优化)