目录名称

一.逻辑架构

1、MySQL的基本架构示意图

alt

2、MySQL逻辑架构结构

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

(1)Server层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

(2)而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是InnoDB,它从MySQL 5.5.5版本开始成为了默认存储引擎。建表时使用engine=InnoDB, 来指定使用内存引擎创建表。

3、各组件作用

(1)连接器

mysql -h$ip -P$port -u$user -d$database
如:mysql -h 127.0.0.1 -P 3306 -u account -D database

alt

① show processlist 显示用户正在运行的线程。

alt

② 参数说明:

Command:多种类型,若显示为“Sleep”表示空闲连接,由参数wait_timeout控制的,默认值是8小时,超过则自动断开,若断开再请求连接报错Lost connection to MySQL server during query,尽量使用长连接;

Info: 一般记录的是线程执行的语句。默认只显示前100个字符,也就是你看到的语句可能是截断了的,要看全部信息,需要使用 show full processlist;

③ 为什么MySQL占用内存涨得特别快

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

如何解决MySQL占用内存涨得特别快?

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

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

④ 常用的sql

#按客户端 IP 分组,看哪个客户端的链接数最多
select client_ip,count(client_ip) as client_num from (select substring_index(host,':' ,1) as client_ip from processlist ) as connect_info group by client_ip order by client_num desc;

#查看正在执行的线程,并按 Time 倒排序,看看有没有执行时间特别长的线程
select * from information_schema.processlist where Command != 'Sleep' order by Time desc;

#找出所有执行时间超过 5 分钟的线程,拼凑出 kill 语句,方便后面查杀
select concat('kill ', id, ';') from information_schema.processlist where Command != 'Sleep' and Time > 300 order by Time desc;

(2)查询缓存

MySQL拿到一个查询请求后,先查缓存,结果以key-value对的形式,被直接缓存在内存,查询缓存往往弊大于利,因为对表更新缓存就会失效。

参数query_cache_type设置成DEMAND,这样对于默认的SQL语句都不使用查询缓存,也可使用SQL_CACHE显式指定去查询缓存的语句,sql如下:

select SQL_CACHE * from T where ID=10;

注意:MySQL 8.0版本直接将查询缓存的整块功能删掉了。

(3)分析器

分析器先会做“词法分析”,如把字符串“T”识别成“表名T”,把字符串“ID”识别成“列ID”;再做“语法分析”,根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法。

(4)优化器

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。

(5)执行器

开始执行的时候,先判断一下对这个表T有没有执行查询的权限,如果有则打开表继续执行,执行器就会根据表的引擎定义,去使用这个引擎提供的接口(引擎中已经定义好的)。可以在数据库的慢查询日志中看到一个rows_examined的字段,表示这个语句执行过程中扫描了多少行。

在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟rows_examined并不是完全相同的

4.思考题

如果表T中没有字段k,而你执行了这个语句 select *fromTwhere k=1, 那肯定是会报“不存在这个列”的错误: “Unknown column ‘k’ in ‘where clause’”。你觉得这个错误是在我们上面提到的哪个阶段报出来的呢?

答案:优化器,优化器会进行优化分析,比如用先执行哪个条件,使用哪个索引,如果没有对应的字段就会报错的。MySQL确实在设计上受Oracle影响颇深,分析器做了这个工作。