SQL的执行顺序:from—where–group by—having—select—order by
MVCC,redolog,undolog,binlog
-
undolog,也就是常说的日志回滚文件,主要用于事务执行失败进行回滚,以及MVCC中对于数据历史版本的查看。
由InnoDB引擎实现,是逻辑日志,记录数据修改之前的值,比如“id=8”修改为“id=81”,那么undolog就会存放“id=8”的记录。当一个数据需要修改,那么就会把修改前的记录存储在undolog中,如果修改出现异常,那么就会使用undolog实现回滚操作,以此保证事务的一致性。
如果事务提交后,undolog并不会立即删除,而是放到清理链表中,等判断没有事务会用到该版本的信息时就会清理undolog。undolog保存了事务发生之前数据的一个版本,用于回滚,同时提供多版本并发控制下的读(MVCC),也即非锁定读。 -
redolog是重做日志文件,记录了数据修改之后的值,用于持久化到磁盘中。
redolog包括两个部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。
由InnoDB引擎实现,是物理日志,记录了物理数据页修改的信息,比如“某个数据页上的内容有哪些发生了改动”。
当一条数据需要更新时,InnoDB会将数据更新,然后记录在redolog内存中,然后再找时间将redolog的操作执行到磁盘上。但是不管提交与否,都会记录,如果回滚,那么回滚也会记录。这样就确保了事务的持久性。 -
MVCC,多版本并发控制,是mysql基于乐观锁理论实现隔离级别的方式,是读已提交和可重复读隔离级别的实现。
在mysql中,会在表中每一条数据后面添加两个字段:最近修改该行数据的事务id,还有指向该行(undolog表中)回滚段的指针。
Read View判断行的可见性,创建一个新的事务时,copy一份当前系统中的活跃事务列表,也就是当前不应该被本事务看到的其他事务id列表。 -
binlog,由mysql服务层实现,是逻辑日志,记录sql语句的原始逻辑,比如id=“8”修改为id=“81”。binlog会写入到指定大小的物理文件中,是追加写入,当前文件写满就会创建新的文件写入。
产生:事务提交的时候,一次性将事务中sql语句,按照一定的格式记录到binlog中。用于复制或恢复在主从复制中,从库利用主库上的binlog进行重播(执行日志中记录的修改逻辑),实现主从同步。业务数据出错,用binlog恢复。
binlog和redolog的区别
- redolog是在InnoDB存储引擎层产生,而binlog是MySQL数据库的上层服务层产生的。
- 两种日志记录的内容形式不同。MySQL的binlog是逻辑日志,其记录是对应的SQL语句。而innodb存储引擎层面的重做日志是物理日志。
- 两种日志与记录写入磁盘的时间点不同,binlog日志只在事务提交完成后进行一次写入。而innodb存储引擎的重做日志在事务进行中不断地被写入,并日志不是随事务提交的顺序进行写入的。
- binlog不是循环使用,在写满或者重启之后,会生成新的binlog文件,redolog是循环使用。
- binlog可以作为恢复数据使用,主从复制搭建,redolog作为异常宕机或者介质故障后的数据恢复使用。
Mysql如何保证一致性和持久性
MySQL为了保证ACID中的一致性和持久性,使用了WAL(Write-Ahead Logging,先写日志再写磁盘)。Redo log就是一种WAL的应用。当数据库忽然掉电,再重新启动时,MySQL可以通过Redo log还原数据。也就是说,每次事务提交时,不用同步刷新磁盘数据文件,只需要同步刷新Redo log就足够了。
InnoDB的行锁模式
• 共享锁(S):用法lock in share mode,又称读锁,允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
• 排他锁(X):用法for update,又称写锁,允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。在没有索引的情况下,InnoDB只能使用表锁。
为什么选择B+树作为索引结构
• Hash索引:Hash索引底层是哈希表,哈希表是一种以key-value存储数据的结构,所以多个数据在存储关系上是完全没有任何顺序关系的,所以,对于区间查询是无法直接通过索引查询的,就需要全表扫描。所以,哈希索引只适用于等值查询的场景。而B+ 树是一种多路平衡查询树,所以他的节点是天然有序的(左子节点小于父节点、父节点小于右子节点),所以对于范围查询的时候不需要做全表扫描
• 二叉查找树:解决了排序的基本问题,但是由于无法保证平衡,可能退化为链表。
• 平衡二叉树AVL:通过旋转解决了平衡的问题,但是旋转操作效率太低。
• 红黑树:通过舍弃严格的平衡和引入红黑节点,解决了 AVL旋转效率过低的问题,但是在磁盘等场景下,树仍然太高,IO次数太多。
• B+树:在B树的基础上,将非叶节点改造为不存储数据纯索引节点,进一步降低了树的高度;此外将叶节点使用指针连接成链表,范围查询更加高效。
B+树的叶子节点都可以存哪些东西
可能存储的是整行数据,也有可能是主键的值。B+树的叶子节点存储了整行数据的是主键索引,也被称之为聚簇索引。而索引B+ Tree的叶子节点存储了主键的值的是非主键索引,也被称之为非聚簇索引
覆盖索引
指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。
查询在什么时候不走(预期中的)索引
- 模糊查询 %like
- 索引列参与计算,使用了函数
- 非最左前缀顺序
- where对null判断
- where不等于
- or操作有至少一个字段没有索引
- 需要回表的查询结果集过大(超过配置的范围)
数据库优化指南
- 创建并使用正确的索引
- 只返回需要的字段
- 减少交互次数(批量提交)
- 设置合理的Fetch Size(数据每次返回给客户端的条数)