MySQL - 查询

132 阅读4分钟

这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战

MySQL的构成 - Server层和存储引擎层

  • Server层主要包含:连接器、存储缓存、分析器、优化器、执行器、内置函数、跨存储功能(触发器、视图、存储过程)
  • 存储引擎层主要是用来对数据进行存储和提取。其架构模式是插件式,支持InnoDB、MyISAM、Memory

多个存储引擎共用一个Server层 主要的流程如图所示:

image.png 以下就通过MySQL的构成来分析整个查询语句的流程

连接器:与客户端创建连接、用户权限、管理和维护连接

连接器的主要步骤如下:

  1. 首先通过命令 mysql -hip−pip -pip−pport -u$user -p
  2. 窗口输入密码【直接在命令行中输入密码容易导致密码泄露,尤其是连接生产服务器时】
  3. 连接器通过用户名和密码对用户进行身份认证。
    • 如果用户名或密码错误。则输出 Access denied for user。客户端程序结束执行
    • 如果用户名和密码正确,则连接器通过权限表读取到当前用户的权限。
    • 之后的权限判断逻辑也会依赖于此时读取到的权限信息。一旦连接成功,即使此时用户管理员修改了该用户的权限,也不会影响。除非断开连接后重新连接才会使用新授权的权限。
    • 如果连接成功后客户端不做任何操作,此时的连接处于空闲状态。如果输入命令 show processlist 可以看到command 为sleep。
    • 如果客户端长时间没有进行连接,则会自动断开。自动断开是由参数wait_timeout所控制的,默认值是8小时
    • 连接断开后如果再次发送请求,则会出现 “lost connection to mySQL server during query”

长连接 VS 短连接

长连接:客户端持续有请求 - 一直使用同一个连接
短链接:每次执行完少数几次查询后就断开连接,下次查询再重新建立一个

由于连接过程比较复杂,因此建议使用中尽可能地减少连接动作,也就是使用长连接

但如果一直是长连接,由于MySQL在执行过程中临时使用的内存是管理在连接对象里,只有连接断开时才会释放。因此积累下来可能会出现内存占用太大,被系统强行杀掉(OOM)。MySQL呈现异常重启的状态。 因此对于以上情况有两种解决方案:

  1. 一段时间断开长连接:固定一个时间/程序里面判断执行过一个占用内存较大的查询后
  2. mySQL5.7/更新版本 - 每次执行一个比较大的操作后,通过执行mysql_reset_connection来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚建立连接的状态

存储缓存

  • 存储缓存是连接建立完成后,MySQL拿到一个查询请求,可以先到查询缓存中看一下该语句是否已经执行过。
  • 查询缓存会讲语句和结果以key-value的方式存储下来。如果找到了key值,就直接将value返回。
  • 如果没有找到就继续后面的操作,并将返回的结果存到存储缓存中。
  • 但存储缓存的弊大于利。因为一旦有对表的更新操作,所有查询缓存就会被全部清空。对于更新压力大的数据库,查询缓存的命中率就会很低。
  • 因此可按需使用 - 将参数query_cache_type设置成DEMAND。则默认的SQL语句不使用查询缓存,确定要使用的,用SQL_CACHE显式指定。

分析器

  • 分析器首先是进行词法分析 - 识别出里面的字符串分别是什么,代表什么意思
  • 然后语法分析 - 根据mySQl的语法规则去判断是否满足MySQL语法

优化器

  • 有索引时,决定使用哪个索引
  • 多张表关联时,决定各个表的连接顺序

执行器

  • 开始执行语句

  • 判断有无查询权限

    • 没有权限 - 报错
    • 有权限 - 打开表,根据表的引擎定义,去使用这个引擎提供的接口 对权限的检查为什么不在优化器之前做?
  • 因为有时候要操作的表不仅仅是SQL语句字面意义上的那些。比如触发器得在执行器的过程中才能确定,优化器阶段前无能为力。