• MySQL 服务端整体架构和 SQL 查询语句的执行流程


    MySQL 数据库客户端成功建立与服务端的连接和并完成用户认证后,就可以发送 SQL 语句与服务端交互了:

    -w848

    接下来,我们一起来探究当客户端发送一个 SQL 查询语句后,服务端都做了哪些操作,将最终结果返回给客户端。

    服务端整体架构

    开始之前,我们先来看看 MySQL 服务端的整体架构:

    mysql_arch.jpg

    可以看到服务端主要由 Server 层和存储引擎两部分组成:

    • Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
    • 存储引擎层负责数据的存储和提取,其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。我们后续教程也主要基于 InnoDB 进行讲解。

    对 MySQL 服务端架构有了整体了解后,接下来,我们来依次探究一条 SQL 查询语句到达服务端后,在每个组件中都经历了什么。

    由于现在客户端已经建立了与服务端的连接,所以连机器这一步就可以跳过了,我们接着往下看。

    查询缓存

    当 MySQL 服务端拿到一条 SQL 查询语句后,首先会查询缓存,看之前是不是执行过这条语句。如果执行过,会缓存在内存中,这个时候直接返回之前缓存的查询结果给客户端即可;如果在缓存中没有找到对应的记录,就会继续后面的操作,并且在最终执行完成后,将查询结果保存到查询缓存。

    可以看到,如果命中查询缓存,MySQL 不需要执行后面的复杂操作就可以直接返回结果,查询效率会很高。但是通常不建议这么做,原因和是否要在业务逻辑中保存模型类查询结果一样:因为这个缓存的 key 是查询语句,只要有一点不同(实际项目中查询字段、查询条件千姿百态)就会导致缓存命中失败,同时,数据表记录本身也是不断更新(插入、更新、删除)的,更新之后,之前的查询缓存就全部失效了,所以从维护成本和实际收益上看,得不偿失。除非这张表创建初始化后不怎么更新,是一个静态表,并且查询语句相对单一。

    注:MySQL 8.0 版本开始将不再支持查询缓存功能。

    你可以通过 show variables like '%query_cache%'; 语句查看系统查询缓存设置:

    -w538

    query_cache_typeOFF 表示默认关闭。你可以在配置文件中配置该值来决定是否启用查询缓存。

    分析器

    如果查询缓存没有启用或者没有命中,就开始真正执行 SQL 查询语句了。

    MySQL 会通过分析器对 SQL 语句做词法分析,以确定到底要做什么,比如 select 表示查询语句,update 表示更新语句等,表名是什么,查询的字段有哪些,查询的条件是什么。

    确定要做的事情之后,分析器还会对 SQL 语句进行语法分析,以确保符合 MySQL 语法,你可能对 You have an error in your SQL syntax 这个报错很熟悉,这就是 SQL 语句语法错误的提示(重点关注「use near」后面的错误原因):

    -w734

    优化器

    如果 SQL 语句词法和语法分析都没有问题,接下来,会经由优化器生成执行计划,这里面主要的工作是数据表包含索引的时候,判定是否使用索引,以及使用哪些索引效率最高(扫描行数最少),我们可以在执行一个 SQL 查询语句之前通过 explain 语句查看它的执行计划:

    -w1247

    注:关于返回结果字段的解释我们在后面会专门介绍,这里先了解即可。

    执行器

    通过分析器可以知道客户端发送的 SQL 语句要做什么,通过优化器可以确定要怎么做,最后就是真正去执行了,这一步通过服务端的执行器完成。

    在根据执行计划执行 SQL 查询语句时,会先验证权限,有相应的权限才会继续执行,否则会报权限错误。

    在具体执行查询操作时,是通过调用存储引擎提供的 API 接口完成的,MySQL 支持不同的存储引擎,虽然这些存储引擎存取数据的底层实现不尽相同,但是对 Server 层提供了统一的接口,执行器调用这些接口可以完成诸如读取下一行记录、插入记录、更新记录之类的日常数据库操作,执行 SQL 查询返回所有满足条件的结果集也是如此。

    在存储引擎中进行查询操作时,如果 SQL 语句没有使用索引,则需要一条条遍历数据表的所有记录(全表扫描),然后将满足条件的记录存放到结果集,直到数据表最后一行,最后再把这个结果集返回给客户端。如果数据表非常大,表记录非常多时,这种查询的效率会很低下,这是我们在优化数据库查询效率时所要极力避免的现象。

    反之,如果 SQL 查询语句中使用了索引,则可以极大提升查询效率,至于底层的原因,我们后面介绍存储引擎底层实现和索引时,会专门进行介绍。

  • 相关阅读:
    python 检测mobileprovision证书的过期时间
    dynamodb 分区键排序键介绍
    dynamodb 基本操作
    Python 实现一个栈
    openstack阅读链接
    mongoengine文档
    机器学习链接
    mongoengine的使用
    Timer(让函数定时执行)
    线程,进程,IO多路复用,协程的代码
  • 原文地址:https://www.cnblogs.com/aipiaoborensheng/p/13650780.html
Copyright © 2020-2023  润新知