Select * from user的千层套路
作为一个程序员,可以说是无时无刻不与sql语句进行打交道,可是你真的了解MySQl的基本框架吗?以及你所写的每一条SQL是如何运行的吗?就比如下面这条平平无奇的SQL语句:
select * from user where id='1';
对于这么一条简单的不能再简单的sql语句来说mysql服务器做了哪些处理呢?下面我们将说一下关于mysql数据库中对sql语句的处理逻辑
MySql的基本架构
要想要了解sql语句的内部处理逻辑,我们需要先学习Mysql的基本架构图,这样才能醍醐灌顶,有更加整体的把握
从这个MySQL的架构图中我们可以看到大体来说MySQL的架构分为两层,分别是:Server层和存储引擎层。
其中Server层是公有的,而存储引擎层是以插件的形式进行扩展的。对于MySQL来说,常见的存储引擎有:InnoDB和MyISAM
而且我们也可以从中看出一条SQL语句从开始运行到最后展出执行结果大概会经历:连接管理、解析与优化以及最后到存储引擎这三关。
下面我们就分别分析一下这三关都有啥具体的内容,Let's go!
连接管理
连接管理是SQL语句执行过程中的第一关,控制着客户端和Server服务端的交互,连接管理主要工作是客户端的身份认证和连接线程的管理。
每个客户端与Server建立连接时,服务器会创建一个线程来与客户端交互,交互的第一项内容就是验证客户端的身份,认证凭证是基于客户端发起连接请求时携带的主机信息、用户名、密码。
如果认证失败,则结束连接任务,并且返回Access denied for user的错误
如果认证成功,还会到权限表中查询该用户的权限,在此次连接下,后续的权限判断都是基于此时读取的权限为依据。
所以说权限是在一开始连接管理的时候就已经确定了。
其次是负责客户端与服务端进行连接,连接管理也做了优化,并不是每个客户端执行完任务之后,就把该线程销毁,而是由连接管理将这些线程缓存起来,等待新的连接,这也就不会频繁的创建和销毁线程,从而节约了开销。
解析与优化
完成连接管理之后,SQL 语句执行的第二步就是解析和优化,SQL 语句查询的所有操作都在这里进行处理。在此过程中首先就是要查询缓存。
查询缓存
MySQL 服务器拿到查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。
但是实际使用中会有很多问题:
命中率低下:只要有稍微的不同就不会命中
缓存数据发送了变化,导致取到错误数据
一旦表中数据或结构改变了缓存也会删除
所以缓存对 MySQL 数据库来说弊大于利,所以在 MySQL 8.0 版本直接将查询缓存的整块功能删掉了
语法解析和预处理
如果查询缓存没有命中,接下来就需要进入正式的查询阶段了。因为客户端程序发送过来的请求只是一段文本而已,所以 MySQL 服务器程序首先要对这段文本做语法解析。
首先通过关键字将 SQL 语句进行解析,并且生成一个“解析树”。MySQL 解析器将使用 MySQL 语法规则验证和解析查询,例如,关键字是否使用正确、关键字的顺序是否正确或者引号是否前后匹配等。
预处理是根据一些 MySQL 规则进一步检查解析树是否合法,例如数据表和数据列是否存在,还会解析名字和别名,看看他们是否有歧义等。
查询优化
MySQL 的优化程序会对我们的语句做一些优化,如外连接转换为内连接、表达式简化、子查询转为连接等等。优化的结果就是生成一个执行计划,这个执行计划表明了应该使用哪些索引进行查询,表之间的连接顺序是啥样的。
执行器
执行器会执行查询优化后的执行计划,通过与存储引擎交互,完成数据的查询操作,返回最终的数据结果。
首先会判断是否有该表权限。
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。
比如我们这个例子中的表 user 中,假设 ID 字段没有索引,那么执行器的执行流程是这样的:
调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 1,如果不是则跳过,如果是则将这行存在结果集中;
调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。
到这里,执行 SQL 语句就执行完了。
存储引擎
到上面为止,SQL 语句就执行完了,但是与真实数据打交道的是存储引擎,存储引擎是 MySQL服务器对数据的存储和提取操作的封装模块。我们知道表是由一行一行的记录组成的,但这只是一个逻辑上的概念,物理上如何表示记录,怎么从表中读取数据,怎么把数据写入具体的物理存储器上,这都是存储引擎负责的事情。
为了实现不同的功能,MySQL提供了各式各样的存储引擎,不同存储引擎管理的表具体的存储结构可能不同,采用的存取算法也可能不同。比如,MySQL5.7 之后默认的 InnoDB 存储引擎。
InnoDB
InnoDB是一个事务型的存储引擎,有行级锁定和外键约束,提供了具有提交、回滚和崩溃回复的事务安全,但是对比MyLSAM引擎,写的效率会差一些,并且会占用更多的磁盘空间以保持数据和索引
特点:
更新多的表,适合处理多重并发的更新请求
支持事务
可以从灾难中恢复(从bin-log日志等)
外键约束,支持外键
支持自动增加列属性auto_increment
MylSAM
MylSAM存储引擎独立于操作系统,系统兼容性好。在建表的时候会创建三个文件,分别是.fm,.MYD,.MYI。这样会导致对大文件的操作慢,但是由于.MYD单独存放数据自然可以优化数据库的查询等操作
.fm:存储表的定义,即表结构
.MYD:存储表里面的数据
.MYI:存储所以
特点:
不支持事务
不支持外键
查询速度快,但是如果数据库表insert和update操作多的话由于采用表锁导致效率低
对表进行加锁
最后
如果觉得看完有收获,希望能给我点个赞,这将会是我更新的最大动力,感谢各位的支持
欢迎各位关注我的公众号【java冢狐】,专注于java和计算机基础知识,保证让你看完有所收获,不信你打我
如果看完有不同的意见或者建议,欢迎多多评论一起交流。感谢各位的支持以及厚爱。