从 MySQL 架构来理解,咱们能够把 MySQL 拆解成几个零件,以下图所示mysql
大致来讲,MySQL 能够分为 Server层 和 存储引擎层两部分。sql
Server 层包括链接器、查询缓存、分析器、优化器、执行器,涵盖MySQL的大多数核心服务功能,以及全部的内置函数(如日期、时间、数学和加密函数等),全部跨存储引擎的功能也在这一层实现,包括 存储过程、触发器、视图等。数据库
存储引擎层负责数据的存储和提取。包括 MySQL 常见的存储引擎,包括 MyISAM、InnoDB 和 Memory 等,最经常使用的是 InnoDB,也是如今 MySQL 的默认存储引擎。
存储引擎也能够在建立表的时候手动指定,使用以下语句:缓存
CREATE TABLE t (i INT) ENGINE = <Storage Engine>;
不一样存储引擎的表数据存取方式不一样,支持的功能也不一样。
从图中能够看出,不一样的存储引擎共用一个Server层,也就是从链接器到执行器的部分。架构
首先须要在 MySQL 客户端登录才能使用,因此须要一个链接器来链接用户和 MySQL 数据库,咱们通常是使用函数
mysql -h<host> -P<port> -u<用户名> -p[<密码>]
来进行 MySQL 登录,和服务端创建链接。优化
虽然密码能够直接跟在
-p
后面写在命令行中,但这样可能会致使你的密码泄露。强烈建议不输入密码,直接运行命令,而后再再交互对话框中输入密码。
在完成 TCP 握手
后,链接器会根据你输入的用户名和密码验证你的登陆身份。若是用户名或者密码错误,MySQL 就会提示 Access denied for user
,而后客户端程序结束执行。若是用户名密码认证经过,链接器会到权限表里面查出你拥有的权限。以后,这个链接里面的权限判断逻辑,都将依赖于此时读到的权限。加密
这就意味着,一个用户成功创建链接后,即便你用管理员帐号对这个用户的权限作了修改,也不会影响已经存在链接的权限。修改完成后,只有再新建的链接才会使用新的权限设置。
链接完成后,若是没有后续的动做,这个链接就处于空闲状态,可使用 show processlist
命令中看到它。spa
mysql> show processlist; +--------+-------------+---------------------+--------+---------+------+----------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +--------+-------------+---------------------+--------+---------+------+----------+------------------+ | 214416 | master | 124.126.130.4:29734 | db_name | Sleep | 13 | | NULL | | 214417 | master | 124.126.130.4:29754 | db_name | Query | 0 | starting | show processlist | +--------+-------------+---------------------+--------+---------+------+----------+------------------+ 2 rows in set (0.07 sec)
其中的Command列显示为 Sleep
的这一行,就表示如今系统里面有一个空闲链接。客户端若是太长时间没动静,链接器就会自动将它断开。这个时间是由参数 wait_timeout
控制的,默认值是8小时。命令行
若是在链接被断开以后,客户端再次发送请求的话,就会收到一个错误提醒: Lost connection to MySQL server during query
。这时候若是你要继续,就须要重连,而后再执行请求了。
数据库里面,长链接是指链接成功后,若是客户端持续有请求,则一直使用同一个链接。短链接则是指每次执行完不多的几回查询就断开链接,下次查询再从新创建一个。
创建链接的过程一般是比较复杂的,因此建议在使用中要尽可能减小创建链接的动做,也就是尽可能使用长链接。
可是所有使用长链接后,你可能会发现,有些时候MySQL占用内存涨得特别快,这是由于MySQL在执行过程当中临时使用的内存是管理在链接对象里面的。这些资源会在链接断开的时候才释放。因此若是长链接累积下来,可能致使内存占用太大,被系统强行杀掉(OOM),从现象看就是MySQL异常重启了。
怎么解决这个问题呢?你能够考虑如下两种方案。
mysql_reset_connection
来从新初始化链接资源。这个过程不须要重连和从新作权限验证,可是会将链接恢复到刚刚建立完时的状态。链接完成后,你就能够执行 SQL 语句了,这行逻辑就会来到第二步:查询缓存。
MySQL 在获得一个执行请求后,会首先去 查询缓存 中查找,是否执行过这条 SQL 语句,以前执行过的语句以及结果会以 key-value 对的形式,被直接放在内存中。key 是查询语句,value 是查询的结果。若是经过 key 可以查找到这条 SQL 语句,就直接返回 SQL 的执行结果。
若是语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果就会被放入查询缓存中。能够看到,若是查询命中缓存,MySQL 不须要执行后面的复杂操做,就能够直接返回结果,效率会很高。
可是大多数状况下,不建议使用查询缓存
由于查询缓存的失效很是频繁,只要在 MySQL 中对某一张表执行了更新操做,那么这张表上的全部的查询缓存就会失效,对于更新频繁的数据表来讲,查询缓存的命中率会很是低。除非你的业务就是有一张静态表,很长时间才会更新一次。好比,一个系统配置表,那这张表上的查询才适合使用查询缓存。
好在MySQL也提供了这种“按需使用”的方式。你能够将参数 query_cache_type
设置成 DEMAND
,这样对于默认的SQL语句都不使用查询缓存。而对于你肯定要使用查询缓存的语句,能够用 SQL_CACHE
显式指定:
select SQL_CACHE * from T where ID=10;
须要注意的是,MySQL 8.0版本直接将查询缓存的整块功能删掉了。
若是没有命中查询缓存,就要开始真正执行 SQL 语句了。
首先,MySQL 会根据你写的 SQL 语句进行解析,分析器会先作 词法分析,你输入的是由多个字符串和空格组成的一条 SQL 语句,MySQL 须要识别出里面的字符串是什么,表明什么。
而后进行 语法分析,根据词法分析的结果, 语法分析器会根据语法规则,判断你输入的这个 SQL 语句是否知足 MySQL 语法。若是 SQL 语句不正确,就会提示 You have an error in your SQL syntax
。
通过分析器的词法分析和语法分析后,这条 SQL 就合法了,MySQL 就知道你要作什么了。可是在执行前,还须要通过优化器的处理。
优化器是在表里面有多个索引的时候,决定使用哪一个索引;或者在一个语句有多表关联(join)的时候,决定各个表的链接顺序。好比你执行下面这样的语句,这个语句是执行两个表的join:
select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
这两种执行方法的逻辑结果是同样的,可是执行的效率会有不一样,而优化器的做用就是决定选择使用哪个方案。
优化器会判断你使用了哪一种索引,使用了何种链接,肯定效率最高的执行方案。
MySQL 经过分析器知道了你的 SQL 语句是否合法,你想要作什么操做,经过优化器知道了该怎么作效率最高,而后就进入了执行阶段,开始执行这条 SQL 语句。
开始执行的时候,MySQL 首先会判断你对要操做的表有没有执行这条语句的权限。
ERROR 1142 (42000): SELECT command denied to user 'foo'@'localhost' for table 'bar'
)。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口查询数据返回给客户端。
至此,MySQL 对于一条语句的执行过程也就完成了。
参考《MySQL实战45讲》丁奇