注意:不同的存储引擎共用一个Server层
所谓连接器,就是我们要连接到MySQL服务器上,即执行:
mysql -uroot -p
接下来会输入密码,如果输入正确,连接器会到权限表里面查出你拥有的权限,之后,这个连接里面的权限判断逻辑,都将依赖于此时读取到的权限;
当一个用户建立连接后,即使你用管理员账号对这个用户的权限做了更改,也不会影响已经连接的客户的权限,修改完成之后,只有再新建的连接才会使用新的权限设置;
在客户端连接之后,如果太长时间没有任何操作,就会自动断开连接,默认8小时(wait_timeout参数控制),数据库分为长连接和短连接:
在有时候使用长连接,会发现MySQL占用内存涨的特别多,这是因为MySQL在执行过程中临时使用的内存是管理在连接对象里的,这些资源在断开连接的时候才会释放,如果长连接累计下来,可能导致内存占用过大,被系统强行杀掉(OOM),代表着MySQL强行重启了;
解决方案:
建立好连接之后,就是执行select语句了,执行的下一步就是查询缓存了;
MySQL拿到一个查询请求之后,会先到查询缓存看看,之前是不是执行过这条语句,之前如果执行过的语句,就会以key–value的形式放入查询缓存中,如果你的查询(key)能在查询缓存里查找到,就可以直接返回这个value; 如果查询语句不在查询缓存中,再执行后面流程,最后查询到了再将结果存入缓存中;
可以看到,能从查询缓存里取结果免去了后面的步骤,效率自然会很高!
但是一般建议不要使用查询缓存,原因有以下几点:
所以,MySQL把查询缓存的使用权交给了用户,你按照自己的需求去决定是否使用
可以将参数query_cache_type设置成DEMAND,这样对于默认的SQL语句都不适用查询缓存,而对于你确定要使用查询缓存的语句,可以如下指定:
select SQL_CACHE * from user;
注意:MySQL 8.0 以后直接删掉了缓存查询这个功能
如果没有命中缓存,就来到这一步了,分析器的功能如下:
经过了分析器后,MySQl就知道你的语句要做什么了,但在开始执行前,还得经过优化器的处理;
优化器的功能为:
mysql> select * from user join orders using(id) where user.sex='1' and
-> orders.id < 10;
例如上面的连接查询(注意使用using时,关联两个表的属性名必须相同),有两张方式去执行:
这两种执行方法的逻辑结果是一样的,但是执行的效率会有所不同,而优化器的工作就是去抉择使用哪一种方案;
经过上面流程,接下来就开始真正的执行MySQL语句了;
例子:
mysql> select * from user where id = 10;
+----+----------+------------+------+---------+
| id | username | birthday | sex | address |
+----+----------+------------+------+---------+
| 10 | tom | 2014-07-10 | 1 | BJ |
+----+----------+------------+------+---------+
1 row in set (0.01 sec)
在执行器中的流程大致如下:
上面讲述了查询一条语句的基本流程,那么更新一条语句又是如何执行的呢?
更新和查询的流程其实是差不多的;
例如执行下面的查询语句:
mysql> update user set id=id+1 where id=10;
Query OK, 1 row affected (0.25 sec)
Rows matched: 1 Changed: 1 Warnings: 0
前面也说过,对表的更新会导致这个表的查询缓存全部失效,这就是我们不推荐使用查询缓存的原因!
同样,更新操作同样会走查询操作的那一套流程,只不过更新流程还涉及两个重要的日志模块,它们正是我们今天要讨论的主角:
试想这样一个问题:如果每次更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程IO成本、查找成本都会很高,所以MySQL设计了一种思路来解决这种问题从而提高效率;
具体流程:
当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log中,并更新内存,这个时候更新就算完成了,然后,InnoDB会在适当的时候,将这个操作记录更新到磁盘里面,这个操作往往在系统比较空闲的时候;
InnoDB的redo log是固定大小的,这就引发了一个问题,当redo log记录满的时候,该怎么办?
这时当记录满的时候,就会将一部分更新到磁盘里,就又有新的空间了,过程如下图:
说明:
前面我们讲了,MySQL整体架构来看,分为Server层和引擎层,上面的redo log是InnoDB引擎特有的日志,而Server层也有自己特有的日志,就是binlog——归档日志;
因为最开始MySQL里并没有InnoDB引擎。MySQL自带的引擎是MyISAM,但是MyISAM没有crash-safe的能力binlog日志只能用于归档 ,所以得使用InnoDB的redo log,来保证实现crash-safe能力!
具体的更新流程就如上图,观察后面,你可以发现将redo log的写入拆成了两步,这是为什么呢?
这就是“两阶段提交”,在此之前,我们先来看一下数据库的备份与恢复;
相信大家都听过这样一句话:数据库能恢复到半个月以内的任意一秒的状态;
这是怎么实现的呢?
肯定是得依靠binlog呗!!前面才说到,binlog存放的是所有的逻辑操作,而且采用追加写的形式,如果你的DBA承诺半个月可以恢复,那么备份系统中一定会保存最近半个月的所有binlog,同时系统会定期做整库备份 ,这里的定期具体是多长时间,取决于系统的重要性,可以是一天一备,也可以是一周一备;
好了,那么假如我在9月5日的某一秒状态误删了一个表,我该怎么恢复呢?
为什么一定要两阶段提交呢?
binlog和redo log是两个独立的逻辑,两阶段提交目的就是让这两个状态保持逻辑上一致 ;
如果不用两阶段提交,只会有下面两种情况: (反证法)
(以上面的更新例子来说)
(1)先写redo log再写binlog
(2)先写binlog再写redo log