暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

一条SQL查询语句是如何执行的

猿java 2022-09-20
29

Weiki

读完需要

7
分钟

速读仅需 3 分钟

Hello,大家好,我是 猿 java。

  作为一名 java 后端程序员,MySQL 应该是接触最多的数据库之一,增删改查(CRUD) 更是对 MySQL 的常规操作。当你在编写一条查询语句时,你有好奇过:这条SQL查询语句是如何执行的吗?哪些环节会影响语句的查询效率?今天我们就来扒一扒 SQL 查询语句的执行流。


1. MySQL 架构示意图

   

MySQL 是典型的 C/S 架构,SQL 整个执行流程包括:客户端,Server 层和存储引擎层 三部分。

    备注:C/S 架构,C是指Client客户端,S是指Server服务端。

    2. 模块分析

       


    2.1 客户端

    客户端是指连接使用 MySQL 的终端。常见的 MySQL 客户端有:java 代码,这个是 java 程序员使用最多的,比如 mybatis ORM 框架;navicat 工具,功能强大,能够可视化操作很多种数据库;mysql-cli,这个是 MySQL 官方自带的客户端;还有一些网页版的客户端。


    2.2 Server层

    Server 层是 MySQL 的核心模块,Server 层包含 连接器、查询缓存、分析器、优化器、执行器等核心组件,涵盖了 MySQL 大多数核心服务以及所有的内置函数,诸如 存储过程、触发器、视图等所有跨存储引擎的功能也都在 Server 层实现。下面将分别讲解几个核心组件。

    连接器

    连接器的主要功能是连接管理和权限校验。当客户端请求过来时,首先是和 Server 层的连接器交互。

    下面通过一个实例来讲解连接层的功能,比如,mysql-cli 客户端连接 MySQL Server 的命令:

      mysql> mysql -h 127.0.0.1 -P 3306 -uroot -p

      整个过程分解为:

      输入指令,点击 Enter键后会完成经典的TCP 3次握手,客户端和MySQL Server建立TCP连接。

      连接建立后,连接器开始对请求进行权限校验,如果 Server 层配置需要密码校验,会提醒用户输入密码,密码正确进入下一步,密码错误提醒"Access denied for user";如果 Server 层配置不需要密码校验,则直接进入下一步

      权限验证成功后,连接器会从权限表把当前用户的所有权限查询并缓存起来,权限缓存的生命周期一直到该连接关闭。


      连接器会把权限缓存,因此,只要该连接一直存在就会使用缓存中的权限,这就意味着,即便服务器更改了该用户的权限,只要是在权限更改前还存活的连接,新的权限不生效。这也能很好的解释,有时候服务端修改了权限配置,客户端不能及时生效。

      查询缓存

      缓存是 MySQL 为了加速查询而设置的,当请求鉴权完成之后,就会到执行缓存查询(Server 层开启了缓存),如果命中缓存,则直接返回,否则进入下一步。不过根据小编剧这么多年的工作经验,缓存使用的场景比较少,比如:MySQL 中存放的是一些静态数据或者变更频率特别低,其他的场景这个功能就比较鸡肋了,怎么鸡肋呢?

      因为只要对表有更新操作,查询缓存就会失效,如果表的更新和查询操作比较频繁,那么缓存就会一直处于建立和失效的频繁交替中,最终导致查询性能不但没有提升还无形中多维护了缓存。


      因此实际生产中,Server 层都会设置 query_cache_type=DEMAND,这样 SQL 默认不会使用查询缓存。如果有特殊需求一定要使用查询缓存,可以显示指定 SQL_CACHE,比如下面的 SQL 语句:

        mysql> select SQL_CACHE * from user where id = ?;


        分析器

        分析器,顾名思义就是 SQL 语句进行分析,那么,分析器对 SQL 会做哪些分析呢?通常来说有:词法分析 和 语法分析 两种。

        词法分析 是判断 SQL 里面的字符串进行拆解,识别当前 SQL 是什么操作,SQL 里面包含多少字符串,空格等等,比如:下面的 sql 语句,词法分析器可以根据 select 来判断当前 SQL 是查询操作,id 为需要查询的结果,where 后面的条件等等;

          mysql> select id from user where name = 'zhangsan';


          语法分析就是检查 SQL 的语法是否正确,比如下面的 SQL 语句,把 update 错误的写成了 updater,因此语法分析器就能识别该 SQL 有语法错误,抛出语法错误相关的异常。

            mysql> updater user set update_time = now() where id = 10;


            优化器

            优化器目的是对 SQL 语句进行优化处理。因为 SQL 语句的编写者能力不一样,编写出来的 SQL 语句性能也不一样。Server 层如果完全按照 SQL 语句顺序执行,可能会造成性能问题, 所以需要优化,判断语句能否使用索引等。比如下面的场景:

            假如:5000 万数据的 user 表中原存在一个组合索引是 index_name_age(name,age),某工程师在没有查看现有索引的情况编写了如下的 SQL 语句:

              mysql> select * from user where age = 30 and name like '张%';


              假如 MySQL server 层完全按照 SQl 语句的顺序执行,则该 SQL 语句不会使用索引,必定会成为慢 sql。而有了优化器,语句就可以优化成下面的形式,完全使用上现有的 index_name_age(name,age)索引。这下是不是看出了优化器的好处。

                mysql> select * from user where name like '张%' and age = 30;


                执行器

                执行器就是运行 SQL 语句。不过,此处执行器不会在 Server 层直接执行 SQL 语句,而是根据数据表中执行引擎类型调用对应的存储引擎提的接口。至于,为什么执行引擎不亲自执行 SQL 语句,我们会后期进行分享。不过 MySQL 此处的设计符合了 SOLID 软件设计原则 ( https://www.yuanjava.cn/tags/solid/ ) 的依赖倒置原则。

                2.3 存储引擎层

                   

                存储引擎层负责数据的存储和提取。采用插件式的架构模式,常见的存储引擎有 InnoDB、MyISAM、Memory 等。其中 MyISAM 是 MySQL 官方自带的引擎,但是因为该引擎不支持事务,使得能够支持事务的 InnoDB 存储引擎得以快速发展,并在 MySQL 5.5.5 版本夺嫡成功,成为了默认存储引擎。

                因此,作为开发人员,在进入新公司后,最好是要弄清楚公司的 MySQL 版本以及默认引擎,这样可以避免很多不必要的坑。查看指令如下:

                  # 查看数据库版本
                  mysql> status;


                  # 查看默认引擎
                  mysql> SHOW VARIABLES LIKE 'default_storage_engine%';


                  3. 总结

                     

                  • SQL 执行会经历客户端、Server 层、存储引擎层 3 个部分。

                  • Server 层包含 连接器、查询缓存、分析器、优化器、执行器等核心组件。

                  • 连接器主要职责是管理连接,权限校验

                  • 查询缓存主要职责是为查询提供缓存

                  • 分析器主要职责是词法分析和语法分析,目的是识别 SQL 是做什么,有没有语法错误。

                  • 优化器主要职责是关注 SQL 的性能,优化 SQL 语句怎么更好的去执行,比如:匹配索引,优化 join 查询的连接顺序。

                  • 执行器主要职责是调用存储引擎接口和返回结果。

                  • 存储引擎主要职责是数据的存储和提取,给执行器提供接口。


                  4. 鸣谢

                     

                  如果你觉得本文章有帮助,感谢转发给更多的好友,我们定将呈现更多的干货, 欢迎关注公众号:猿 java


                  往期精彩内容:

                  分布式算法:Paxos 是如何达成共识的?

                  深度剖析IO多路复用机制

                  文章转载自猿java,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                  评论