注:我不是原作者。 我只是在学习的时候参考别人的资料整理出来的,分享给大家,让大家共同学习,共同进步。
前言
我们平时使用数据库的时候,通常都是把它看成一个整体。 例如,如果你有一个最简单的表,执行下面的查询语句时,我们只看到输入了一条语句,返回了一个结果,但我们不知道这条语句在MySQL内部的执行过程。 那么今天我就来拆解MySQL,看看里面都有哪些“零件”。 希望通过这个拆解过程,让我对MySQL有更深入的了解。 这样当我们MySQL遇到一些异常或者问题的时候,我们就可以追根究底,更快的定位和解决问题。
一般来说,MySQL可以分为三个部分:连接器层、存储引擎层。 该层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖了MySQL的大部分核心服务功能,以及所有内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎 该层实现了功能,如存储过程、触发器、视图等。存储引擎层负责数据存储和检索。 其架构模型为插件式,支持 、 、 等多种存储引擎。 现在最常用的存储引擎,从MySQL 5.5.5版本开始已经成为默认的存储引擎。
下面我给出的是MySQL的基本架构示意图,从中可以清晰的看到MySQL各个功能模块中SQL语句的执行过程。
也就是说,执行table建表时,如果不指定引擎类型,就会默认使用引擎类型。 不过,你也可以通过指定存储引擎的类型来选择其他引擎,比如在建表语句中使用=来指定创建表时使用的内存引擎。 不同的存储引擎有不同的表数据访问方式,支持不同的功能。 在后面的文章中,我们将讨论引擎的选择。 从图中不难看出,不同的存储引擎共享一层,即从连接器到执行器。 您可以先对每个组件的名称有一个印象。 接下来我就根据开头提到的SQL语句带大家走一遍整个执行过程,依次看看各个组件的作用。
连接器(手柄连接)
客户端向服务器发送请求,最终收到响应,本质上是一个进程间通信的过程。
MySQL 有一个专门设计来处理连接的模块——连接器。
连接命令一般是这样写的:
mysql -h$ip -P$port -u$user -p
输入命令后,需要在交互对话框中输入密码。 虽然也可以直接在命令行中写在-p后面,但这可能会导致你的密码泄露。 如果您连接到生产服务器,我们强烈建议不要这样做。 连接命令中的mysql是一个客户端工具,用于与服务器建立连接。
客户端与服务器之间的通信方法 TCP/IP协议权限验证
确认通信方法并成功建立连接后,连接器将开始使用您的用户名和密码验证您的身份。
这意味着用户成功建立连接后,即使使用管理员帐户修改用户的权限,也不会影响现有连接的权限。 修改完成后,只有新连接才会使用新的权限设置。
连接完成后,如果没有后续操作,该连接将处于空闲状态,可以在show命令中看到。 文中图片为展示结果。 该列显示“Sleep”的行表示系统中有空闲连接。
如果客户端长时间不活动,连接器将自动断开连接。 该时间由参数控制,默认值为8小时。
如果连接断开后客户端再次发送请求,则会收到错误提醒:Lost to MySQL query。 如果此时想继续,则需要重新连接,然后执行请求。
在数据库中,长连接是指连接成功后,如果客户端继续发出请求,将始终使用同一个连接。 短连接是指执行几次查询后连接就断开,并为下一次查询重新建立新的连接。
建立连接的过程通常比较复杂,所以我建议大家在使用过程中尽量减少建立连接的动作,即尽量使用长连接。
但全部使用长连接后,你可能会发现有时MySQL占用的内存增长得很快。 这是因为MySQL在执行过程中临时使用的内存是在连接对象中管理的。 当连接断开时,这些资源将会被释放。 因此,如果长连接积累起来,可能会占用过多的内存而被系统强行杀死(OOM)。 从现象来看,MySQL异常重启。
如何解决这个问题呢? 您可以考虑以下两种选择。
分析与优化
服务器收到客户端的请求后,还需要经过查询缓存、词法语法分析和预处理、查询优化等。
查询缓存
连接建立后,就可以执行语句了。 执行逻辑会来到第二步:查询缓存。
MySQL收到查询请求后,首先会去查询缓存中查看这条语句之前是否执行过。 之前执行的语句及其结果可以以键值对的形式直接缓存在内存中。 key是查询语句,value是查询结果。 如果你的查询可以直接在此缓存中找到键,那么该值将直接返回给客户端。
如果该语句不在查询缓存中,则执行阶段继续。 执行完成后,执行结果将存储在查询缓存中。 可以看到,如果查询命中了缓存,MySQL就可以直接返回结果,不需要进行后续的复杂操作,效率非常高。
建议不要使用查询缓存,原因如下:
因此,缓存功能交给专业的ORM框架(比如默认开启一级缓存)或者独立的缓存服务Redis比较合适。
注:.0已经完全去掉了缓存功能
解析器
如果查询缓存没有命中,则开始实际执行该语句。 首先,MySQL需要知道你想要做什么,因此它需要解析SQL语句。
词法分析
以下面的SQL语句为例
SELECT id, username FROM `user` WHERE id = '8925ed73074b4a66a64d61c37c16411d'
分析器首先会做“词法分析”,即将一条完整的SQL语句拆成单词,比如一条简单的SQL语句,每个符号是什么类型,在哪里开始和结束。
MySQL将你输入的关键字识别为查询语句。它还需要识别字符串user
将其更改为“表名用户”,将字符串id识别为“列id”,将字符串识别为“列”。
语法分析
完成词法分析后,下一步就是进行语法分析。 根据词法分析的结果,语法分析器会根据语法规则判断你输入的SQL语句是否满足MySQL语法,比如单引号是否闭合、关键字拼写是否正确等。解析器会生成基于SQL语句的数据结构,这个数据结构成为解析树。
预处理器
词法分析和语法分析无法知道数据库中有哪些表和字段。 要了解此信息,您需要在解析阶段使用另一个工具 - 预处理器。
它检查生成的解析树并解析解析器无法解析的语义。 例如,它检查表名和列名是否存在,并检查名称和别名以确保不存在歧义。 经过预处理,得到一棵新的解析树。
解析和预处理本质上是一个编译过程,涉及词法解析、语法和语义分析。 我们不会探讨更多细节。 有兴趣的读者可以阅读有关编译原理的书籍。
查询优化器()和查询执行计划
到这一步,MySQL终于知道了我们要查询的表和列以及对应的搜索条件。 MySQL作者担心我们写的SQL太垃圾,所以他设计了一个叫做查询优化器的东西来帮助我们提高查询效率。 当表中有多个索引时,优化器决定使用哪个索引; 或者当一条语句有多个表关联(连接)时,它决定每个表的连接顺序。
例如,如果执行以下语句,则该语句将执行两个表之间的联接:
select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
这两种执行方式的逻辑结果是一样的,但是执行效率会不同,而优化器的作用就是决定采用哪种方案。
优化器到底做了什么?
举两个简单的例子:
事实上,对于每个数据库来说,优化器模块都是必不可少的。 他们使用复杂的算法来尽可能优化查询效率。
更详细地说,查询优化器主要优化以下几个方面:
注意:但是优化器也不是万能的。 如果SQL语句真的很垃圾,那么再好的优化器也救不了你。 所以大家在写SQL语句的时候还是需要有意识地优化。
执行器
MySQL通过分析器知道你想做什么,通过优化器知道如何做,因此它进入执行器阶段,开始执行语句。
开始执行时,首先要判断自己是否有权限对该表T执行查询,如果没有,会返回无权限的错误。
如果有权限,打开表并继续执行。 当打开表时,执行器将根据表的引擎定义使用引擎提供的接口。
存储引擎 什么是存储引擎
数据应该存储在哪里,内存中还是磁盘上? 如何从表中读取数据以及如何将数据写入特定的表中都是存储引擎的责任。
为什么需要存储引擎
因为存储需求不同。 想象一下:
为什么支持这么多存储引擎? 因为一种存储引擎无法提供所有功能。
存储引擎是计算机抽象的典型代表。 它的作用是接受上层的指令,然后读写表中的数据。 这些操作与上层完全屏蔽。 你甚至可以查阅MySQL文档来定义自己的存储引擎,只要你外部实现相同的接口即可。 存储引擎只是MySQL读写数据的一个插件,可以根据不同的用途随意更换(插拔)。
如何使用存储引擎? 创建表时指定存储引擎
创建表时,可以指定当前表的存储引擎。 如果没有指定,则默认存储引擎。 如果你想明确指定存储引擎,你可以这样做
CREATE TABLE `user` (
`id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '用户ID',
`person_info_id` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '人员编号',
`nick_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '用户昵称',
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '用户名',
`password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '密码',
`avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '头像',
`is_system` tinyint(1) NULL DEFAULT NULL COMMENT '是否是系统内置(1是,0否)',
`status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '帐号状态(枚举维护)',
`last_login_ip` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '上次登陆IP',
`last_login_time` datetime NULL DEFAULT NULL COMMENT '上次登陆时间',
`is_delete` tinyint(1) NOT NULL COMMENT '是否删除(0存在 1删除)',
`created_by` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '创建人',
`created_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`updated_by` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '更新人',
`updated_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '用户表' ROW_FORMAT = DYNAMIC;
not null :表示此列不能为空
primary key :表示主键(唯一且不为空)
engine =innodb :表示指定当前表的存储引擎
default charset utf8mb4 :设置表的默认编码集
修改表的存储引擎
ALTER TABLE 表名 ENGINE = 存储引擎名称;
常见存储引擎对比
应用范围较小,表级锁限制了读写性能。 因此,在Web和数据仓库配置中,通常用于只读或面向读的工作。
特征:
MySQL 5.7 及更高版本中的默认存储引擎。 它是一个事务安全(ACID兼容)的MySQL存储引擎,具有提交、回滚和崩溃恢复功能来保护用户数据。 行级锁定(无需升级为粗粒度锁定)和一致的非锁定读取可提高多用户并发性。 将用户数据存储在聚集索引中,以减少基于主键的常见查询的I/O。 为了维护数据完整性,还支持外键引用完整性约束。
特征:
补充:最初是该公司开发的,与MySQL AB合作开源代码。
但没想到MySQL的竞争对手会收购它。 后来,2008年,Sun(开发了Java语言的Sun)收购了MySQL AB,2009年,Sun又被收购,于是MySQL和SQL 再次成为同一家公司。 有些人认为MySQL变得越来越相似,但实际上就是这个原因。
将所有数据存储在 RAM 中以便快速访问。 该引擎以前称为堆引擎。
特征:
CSV
它的表实际上是带有逗号分隔值的文本文件。 csv 表允许导入或转储 CSV 格式的数据,以便与读写相同格式的脚本和应用程序交换数据。 由于 CSV 表没有索引,因此通常在正常操作期间将数据保存在表中,而仅在导入或导出阶段使用 CSV 表。
特征:
专用和存档的空间被压缩,用于存储和检索大量很少引用的信息。
特征:
如何选择存储引擎