作为一名 JAVA开发人员,写 SQL 语句是常有的事,但是你知道 SQL 语句背后的处理逻辑吗?比如下面这条 SQL 语句:
select * from user where id=1
执行完这条语句后,我们就会得到 id 为 1 的用户信息 。那么对于这一条 SQL 语句,MySQL服务器做了哪些处理呢?这篇文章我们就一起打卡 MySQL 数据库中对 SQL 语句的处理逻辑 。
了解 MySQL 数据库的 SQL 语句内部处理逻辑有什么好处?当我们碰到 MySQL 的一些异常或者问题时,就能够直戳本质,更为快速地定位并解决问题 。想要更好的了解 SQL 语句的内部处理逻辑,我们可以先看 MySQL 的基本架构图,这样我们可以站在更高的角度去俯瞰 MySQL 数据库,MySQL 的基本架构示意图如下:
文章插图
从图中,我们可以清晰的看出 MySQL 的架构和各个模块以及 SQL 语句的执行过程,MySQL 数据库整体可以分为 Server 层和存储引擎层两部分,其中 Server 层是共有的,而存储引擎层则是可以以插件的形式进行扩展 。一条 SQL 语句大概会经历链接管理、解析与优化、最后到存储引擎,这三个模块 。接下来我们就来聊一聊这三个模块 。
连接管理连接管理是 SQL 语句执行过程中碰到的第一关,链接管理就像一扇大门一样,控制着客户端与 Server 服务端的交互,连接管理主要工作是客户端的身份认证和连接线程的管理 。
每个客户端与 Server 建立连接时,服务端都会创建一个线程来与客户端进行交互,交互的第一项内容就是验证客户端的身份,认证凭据是基于客户端发起连接请求时携带的主机信息、用户名、密码 。如果认证失败,则结束连接任务,并且返回的 Access denied for user 错误 。
如果认证成功,连接管理还会做一件事情,到权限表中查询出该用户的权限,在这次连接下,后续的权限判断都是基于此时读取的权限为依据,也就是说连接成功后,即使管理员对这个用户做了权限修改,也不会影响这次连接的权限验证 。
连接管理需要做的事情就比较简单,主要是负责客户端与服务端进行连接,当然在连接线程上,连接管理也做了优化,并不是每个客户端执行完任务之后,就把该线程销毁,连接管理会把这些线程缓存起来,等待新的连接,这也就不会频繁的创建和销毁线程,从而节约了开销 。
解析与优化完成连接管理之后,SQL 语句执行的第二步就是解析和优化,这一步就非常的复杂,SQL 语句查询的所有操作都在这里了 。我们可以将这一步细分为 4 小步 。
查询缓存在 MySQL 服务端也有缓存,这是一个非常鸡肋的功能,为什么呢?看完了你就知道了 。
MySQL 服务器拿到查询请求后,会先到查询缓存看看,之前是不是执行过这条语句 。之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中 。key 是查询的语句,value 是查询的结果 。如果你的查询能够直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端 。如果语句不在查询缓存中,就会继续后面的执行阶段 。执行完成后,执行结果会被存入查询缓存中 。
看上去没毛病,这样做会大大提升 MySQL 的性能,然而,你想多了,MySQL 的查询缓存命中率非常的低,主要原因是如果两个查询请求在任何字符上的不同(例如:空格、注释、大小写),都会导致缓存不会命中 。
还有就是缓存有可能获取到错误的数据,以某些系统函数举例,可能同样的函数的两次调用会产生不一样的结果,比如函数NOW,每次调用都会产生最新的当前时间,如果在一个查询请求中调用了这个函数,那即使查询请求的文本信息都一样,那不同时间的两次查询也应该得到不同的结果,如果在第一次查询时就缓存了,那第二次查询的时候直接使用第一次查询的结果就是错误的!
除了这些之外,MySQL 缓存的失效也非常的频繁,MySQL的缓存系统会监测涉及到的每张表,只要该表的结构或者数据被修改,如对该表使用了 INSERT、 UPDATE、DELETE、TRUNCATE TABLE、ALTER TABLE、DROP TABLE 或 DROP DATABASE 语句,那使用该表的所有高速缓存查询都将变为无效并从高速缓存中删除!
看到这里你知道查询缓存很鸡肋了吧,缓存对 MySQL 数据库来说弊大于利,所以在 MySQL 8.0 版本直接将查询缓存的整块功能删掉了
语法解析和预处理如果查询缓存没有命中,接下来就需要进入正式的查询阶段了 。因为客户端程序发送过来的请求只是一段文本而已,所以 MySQL 服务器程序首先要对这段文本做语法解析 。
推荐阅读
- Linux useradd 命令介绍
- python首行代码import *,from * import * 解析
- Python中from import和import的区别?没有比这更好的回答了
- 深入理解UDP编程
- es6中Array.from和数组去重
- nginx使用set_real_ip_from获取用户真实IP
- 使用userdel命令删除用户账户 如何删除用户账户
- From|《艾尔登法环》不需要乔治马丁
- EXO ‘from happiness’ DVD12月开始销售
- 史上最全Python反爬虫方案汇总