MySQL架构中,引擎层和 server层各自负责什么?

1,449 阅读5分钟

本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力

今天我们来聊聊。关于数据库中架构的那些事儿。

MySQL的架构图

image.png

很多研发工程师都应该看过这张图。张所谓的数据库架构图。

MySQL 可以分为 Server 层和存储引擎层两部分。

本质上。我们当前的数据库。中不同的存储引擎。都用一个server层连接执行器,然后执行语句。

其中存储引擎负责对数据的存储和提取

客户端建立连接

  • 获取权限

  • 管理连接

 

mysql -h$ip -P$port -u$user -p     

 上述是命令行,但是生产服务器就不能这么写了,会泄露你的密码;

一般的本地使用mysql时调用的命令:mysql -uroot -pxxx 中的mysql是指客户端工具,是用来与服务端建立连接的\

Tcp建立连接之后,验证客户端用户名密码,开启认证身份

**
**

如果用户名或密码不对,你就会收到一个"Access denied for user"的错误,然后客户端程序结束执行。

如果正确就会读取权限,在权限表中获取到,修改权限不会影响当前的链接, 重启可以使用新的权限

连接成功后:

 

SHOW PROCESSLIST     //查看这个链接 ,其中command显示sleep就代表 这个是一个空闲链接

  客户端长时间没操作,连接器会在参数wait_timeout,8小时之后断开, 默认是8小时

如果在连接被断开之后,客户端再次发送请求的话,就会收到一个错误提醒: Lost connection to MySQL server during query。这时候如果你要继续,就需要重连,然后再执行请求了。

建立连接过程比较复杂,--通常多数使用长连接-->避免连接动作

但是全部使用长连接后,你可能会发现,有些时候 MySQL 占用内存涨得特别快,这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释放。所以如果长连接累积下来,可能导致内存占用太大,被系统强行杀掉(OOM),从现象看就是 MySQL 异常重启了。

怎么解决这个问题呢?你可以考虑以下两种方案。

  • 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。

  • 如果你用的是 MySQL 5.7 或更新版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。

查询缓存

  当前连接器建立后,  可以执行select的查询语句了,

 

 先不会直接执行,会去缓存中查询根据key_value的形式, key是语句本身,value是执行后的结果,

如果说当前的key已经执行过,那就会找到value直接返回, 如果没有再执行查询语句select

注意事项:

1.缓存需要语句完全相等,包括参数。

2.表更新后就会失效 因此,只有在表更新频率不高,查询语句完全一致的情况下,可以手动开启缓存,其他一律关闭。

 注意:mysql8之后,取消了缓存功能

所以我们一般不使用缓存,因为缓存的弊大于利

 

mysql> select SQL_CACHE * from T where ID=10// SQL_CACHE显示指定用缓存,但是MySQL8.0之后去删除这个功能了

分析器(语句识别)

  如果说当前缓存没有,或者没有命中缓存,就开始直接执行SQL语句了;

语法识别,将参数和关键字逐一识别

优化器

经过分析器的语法分析,代表这个SQL已经是通过标准,可以执行

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如你执行下面这样的语句,这个语句是执行两个表的 join:

也就是优化,链表查询时,哪种效率更快

执行器

MySQL 通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。

通过对分析器分析好的语法,优化器优化好的执行方案--来执行具体的语句;

**
**

执行器会首先看当前语句操作的表,是否有权限, precheck如果有就

**
**

根据当前的存储引擎提供的接口,对语句进行执行,

**
**


 

mysql> select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

比如我们这个例子中的表 T 中,ID 字段没有索引,那么执行器的执行流程是这样的:

  • 调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中;

  • 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。

  • 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。至此,这个语句就执行完成了