文章目录
- MySQL基础架构
- 一、连接器 - 建立连接,权限认证
- 二、查缓存 - 提高效率
- 三、分析器 - 做什么
- 四、优化器 - 怎么做
- 五、执行器 - 执行语句
- 六、存储引擎
- 1、存储引擎的概述
- 2、存储引擎的对比
- 3、存储引擎的命令
- 4、存储引擎的选择
MySQL基础架构
大体来说,MySQL可以分为 Server层
和 存储引擎层
两部分。
Server层
:涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等)- 所有
跨存储引擎
的功能都在这一层实现,比如存储过程、触发器、视图等。
- 所有
存储引擎层
:负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎。
不同的存储引擎共用一个Server层,也就是从连接器到执行器的部分。
一、连接器 - 建立连接,权限认证
连接器:负责跟客户端建立连接、获取权限、维持和管理连接。
# 连接命令
mysql -h 127.0.0.1 -P 3306 -u root -p
# 本机登录(省略 -h ip -P port)
mysql -u root -p
密码也可以直接跟在-p
后面写在命令行中,但这样可能会导致你的密码泄露,所以不建议。
连接命令中的 mysql 是客户端工具,用来跟服务端建立连接。
连接服务包含 本地socket
通信 和 基于客户端/服务端工具实现的类似TCP/IP
的通信。
- 主要完成一些类似于连接处理、授权认证及相关的安全方案。
该层引入了线程池
的概念,为通过安全认证接入的客户端提供线程。
同样在该层上可以实现基于SSL
的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
在完成TCP握手后,连接器开始进行认证:
- 用户名密码错误,会收到一个 “Access denied for user” 的错误,然后客户端程序结束执行。
- 用户名密码正确,连接器会到权限表查出你拥有的权限(之后这个连接的权限判断,都依赖于此时读到的)
这就意味着,一个用户成功建立连接后,即使修改了权限,也不会影响已经存在的连接,只有重新连接才会生效。
连接完成后,如果你没有后续的动作,这个连接就处于空闲状态(
Command
列显示为Sleep
)
# 查看连接列表
show processlist;
客户端如果太长时间没动静,连接器就会自动将它断开。这个时间由参数
wait_timeout
控制,默认值是8
小时
- 长连接:连接成功后,如果客户端持续有请求,则一直使用同一个连接。
- 短连接:每次执行完很少的几次查询就断开连接,下次查询再重新建立一个。
建立连接的过程通常是比较复杂的,因此在使用中要尽量减少建立连接的动作,也就是尽量使用长连接。
全部使用长连接后,你可能会发现,有些时候MySQL占用内存涨得特别快
MySQL在执行过程中,临时使用的内存是管理在连接对象中的,这些资源在连接断开的时候才会释放。所以如果长连接累积下来,可能导致内存占用太大,被系统强行杀掉(OOM),从现象看就是MySQL异常重启了。
怎么解决这个问题呢?可以考虑以下两种方案。
- 定期断开长连接。使用一段时间,或程序里面判断执行过一个占用内存的大查询后,断开连接,之后再重连。
- 如果用的是MySQL 5.7或更新版本,可以在每次执行一个比较大的操作后,执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。
二、查缓存 - 提高效率
执行过的语句及其结果可能会以key-value
的形式,被直接缓存在内存中。key是查询语句,value是查询结果。
select * from T where ID=10;
MySQL拿到一个查询请求后,会先查询缓存,如果查询命中缓存就直接返回结果,否则继续执行后面的操作。
查询缓存的失效
非常频繁,只要有对一个表的更新
,这个表上所有的查询缓存
都会被清空
。因此:
- 不推荐用缓存查询:更新频繁的表
- 推荐使用缓存查询:静态表,很长时间才会更新一次
可以将参数 query_cache_type 设置成 DEMAND,默认不查询缓存。也可以通过查询的时候手动指定,如下:
# 查询缓存
select SQL_CACHE * from T where ID=10;
# 不查询缓存
select SQL_NO_CACHE * from T where ID=10;
注意:MySQL 8.0版本直接将查询缓存的整块功能删掉了,也就是说8.0开始彻底没有这个功能了。
三、分析器 - 做什么
如果没有命中缓存,就开始真正执行语句了。首先,MySQL需要知道你要做什么,因此需要对SQL语句做解析。
- 先做 词法分析:解析 SQL语句 字符串的含义(查询/更新?表名/列名?表/列是否存在?)
- 再做 语法分析:判断 SQL语句 是否符合 语法规则。
四、优化器 - 怎么做
经过了分析器,MySQL就知道你要做什么了。在开始执行之前,还要先经过优化器的处理。
- 在表里面有多个索引的时候,决定 使用哪个索引。
- 在一个语句有多表关联(join)的时候,决定 各个表的连接顺序。
优化器阶段完成后,SQL语句的执行方案就确定下来了。
五、执行器 - 执行语句
进入执行器阶段,开始操作引擎,执行语句:
- 先判断对表T有没有执行查询的权限。如果没有,就返回没有权限的错误。
- 如果有权限,就打开表继续执行。执行器就会根据表T的引擎定义,去调用对应引擎提供的接口。
对于下面的语句,分析执行器的执行流程:
select * from T where ID=10;
- 调用InnoDB引擎接口,“取第一行”,判断ID值是不是10,如果是,则将这行存在结果集中,不是则跳过
- 调用InnoDB引擎接口,“取下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
- 执行器将 上述遍历过程中 所有满足条件的行 组成的记录集 作为结果集返回给客户端。
对于有索引的表,执行的逻辑也差不多:
- 第一次调用 “取满足条件的第一行” 这个接口。
- 之后循环调用 “取满足条件的下一行” 这个接口。
在数据库的慢查询日志中有一个rows_examined
的字段
- 表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。
注意:rows_examined ≠ 引擎扫描行数(某些场景下,执行器调用一次,在引擎内部会扫描多行)
六、存储引擎
存储引擎层真正的负责了MySQL中数据的存储和提取,服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。
1、存储引擎的概述
MySQL中的数据用各种不同的技术存储在文件或内存中,包括存储方式、索引技巧、锁定水平等不同功能。这些不同的技术以及配套的功能被称作存储引擎。
Oracle,SqlServer等数据库只有一种存储引擎。MySQL提供了插件式
的存储引擎架构(多种存储引擎)。 所以MySQL可以根据需要使用相应引擎,或者编写存储引擎。
MySQL 常用的存储引擎有三种: InnoDB 、MyISAM 、MEMORY。创建表时如果不指定存储引擎,系统就会使用默认的存储引擎, MySQL5.5之前 默认是MyISAM,MySQL5.5之后就改为了InnoDB。
2、存储引擎的对比
特点 | InnoDB | MyISAM | MEMORY |
---|---|---|---|
存储限制 | 64TB | 有 | 有 |
事务安全 | 支持 | ||
锁机制 | 行锁,表锁 | 表锁 | 表锁 |
外键 | 支持 | ||
BTree索引 | 支持 | 支持 | 支持 |
Hash索引 | 支持 | ||
全文索引 | 支持(5.6版本后) | 支持 | |
集群索引 | 支持 | ||
数据索引 | 支持 | 支持 | |
索引缓存 | 支持 | 支持 | 支持 |
数据可压缩 | 支持 | ||
空间使用 | 高 | 低 | N/A |
内存使用 | 高 | 低 | 中等 |
批量插入速度 | 低 | 高 | 高 |
3、存储引擎的命令
-- 查看数据库支持的存储引擎
show engines;-- 查询某个数据表的存储引擎
show table status from 数据库名 where name = '数据表名';-- 创建表时指定存储引擎
create table 表名(列名 数据类型 约束,...
) engine = 存储引擎名;-- 修改数据表的存储引擎
alter table 表名 engine = 存储引擎名;-- 设置默认存储引擎
set default_storage_engine = <存储引擎名>
4、存储引擎的选择
# InnoDB(MySQL5.5之后默认的存储引擎)
1. 优点:1)InnoDB 提供了具有提交、回滚、崩溃恢复能力的事务安全。2)InnoDB 采用行锁,适合处理并发写操作。
2. 缺点:会占用更多的磁盘空间以保留数据和索引
3. 场景:1)对事务的完整性和安全性有比较高的要求。2)在并发条件下要求数据的一致性,写多读少。# MyISAM(MySQL5.5之前默认的存储引擎)
1. 优点:1)MyISAM 内存要求低,节约资源。2)MyISAM 采用表锁,读取速度快,查询效率高
2. 缺点:1)不支持事务和外键操作2)不适合并发写操作
3. 场景:1)对事务的完整性、并发性要求不是很高。2)以查询操作为主,只有很少的更新和删除操作,读多写少# MEMORY
1. 特点: 将所有数据保存在内存中,在需要快速定位记录和其他类似数据环境下,可以提供更快的访问。
2. 使用场景:通常用于更新不太频繁的小表,用以快速得到访问结果。