MySQL面试题
MySQL面试题
SQL基础
NOSQL和SQL的区别?
SQL:关系型数据库,数据逻辑以二维表的形式存在,存储结构化数据。
- ACID:支持原子性,一致性,隔离性,持续性
- 水平扩展较难
NOSQL:非关系数据库,数据库逻辑上提供了不同于二维表的存储方式,例如JSON,哈希表等
- BASE:基本可用,软状态和最终一致性
- 非常容易扩展
数据库三大范式是什么?
- 第一范式(1NF):要求数据库表的每一列都是不可分割的原子数据项。
- 第二范式:确保数据库表中每一列都和主键相关,而不知和主键的某一部分相关
- 第三范式:需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
MySQL怎么连表查询
内连接
1
select a.name,b.name form a inner join b on a.id=b.id
左外连接
1
select a.name,b.name form a left join b on a.id=b.id
右外连接
1 | select a.name,b.name form a right join b on a.id=b.id |
- 全外连接
1 | select a.name,b.name form a left join b on a.id=b.id |
MySQL如何避免重复插入数据?
使用UNIQUE约束
1
2
3
4
5create table user (
id INT primary key auto_increment,
email varchar(255) unique,
name varchar(255)
);在表的相关列上添加UNIQUE约束,确保每个值在该列中唯一
使用INSERT … ON DUPLICATE KEY UPDATE
1
2
3insert into user (email,name)
values('420057557@qq.com','dtt')
on duplicate key update name=values(name)这种语句允许在插入记录时处理重复键的情况。如果插入的记录与现有记录冲突,可以选择更新现有记录:
使用INSERT IGNORE: 该语句会在插入记录时忽略那些因重复键而导致的插入错误。例如:
1
2insert ignore into user (email,name)
values('420057557@qq.com','dtt')
使用场景
- 保证全局唯一,用UNIQUE约束
- 需要插入和更新结合用使用
ON DUPLICATE KEY UPDATE
。 - 需要快速忽略重复插入使用,
INSERT IGNORE
CHAR和VARCHARE有什么区别?
- CHAR:固定长度字符串,需指定固定长度,存储时会在末尾补足空格。适合存储固定长度数据。
- VARCHAR:可变长度字符串,需指定最大长度,适合存储可变数据。
Text数据类型可以无限大吗?
不能有最大长度
说一下外键约束
用于维护表与表之间的关系,确保数据的完整性和一致性。
比如,学生表和课程表,一个学生可以选多么课程,一门课程也可以有多名学生选修,这个适合学生表里面的课程id就可以定义为一个外键,用于维护两张表的关系
如果没有外键约束,学生表删除数据而课程表却没有删除该课程学生的情况。
MySQL中的一些基本函数,你知道哪些?
字符串函数
CONCAT(str1,str2):连接多个字符串,返回合并后的结果
1
2select CONCAT('hello',
' ','world !') AS Greeting;length(str):返回字符串的长度
1
select length('hello') as SrtingLength;
SUBSTRING(str,pos,len):截取指定位置的字符串
1
select SUBSTRING('hello world',1,5)AS SubStr
REPLAC(str,form_str,to_str):将字符串的某部分替换成另一个字符串
1
select REPLACE('hello world','world','Redis') as A;
数值函数
ABS(num):返回绝对值
1
select ABS(-10) as a;
POWER(num,exponent):返回数值的幂次方
1
select PORER(2,3) as a;
- 日期和时间函数
- 聚合函数
- count,sum,avg,max,min
存储引擎
执行一条SQL请求的过程是什么?
- 连接器:建立连接,管理连接,教育用户身份。
- 查询缓存:查询语句在缓存中是否命中,命中直接返回,否则继续,MySQL8.0 已删除
- 解析SQL:对sql进行词法分析和语法分析构造语法树,方便后续操作。
- 执行SQL:有三个阶段
- 预处理阶段:检测表或字段是否存在,将
select *
中的*
符号扩展为表上的所有列。 - 优化阶段:优化器主要负责将 SQL 查询语句的执行方案确定下来。
- 执行阶段:根据执行计划执行 SQL 查询语句,从存储引擎读取记录,返回给客户端;
- 预处理阶段:检测表或字段是否存在,将
讲一讲mysql的引擎吧,你有什么了解?
- InnoDB:MySQL默认存储引擎,具有ACID事务支持、行级锁、外键约束等特性。适合高并发读写操作,支持较好的数据完整性和并发控制。
- MyISAM:具有较低的存储空间和内存消耗,适合大量读操作。其它方面有一定限制
- Memory:数据存储在内存,适用于对性能要求较高的读操作。不支持事务、行级锁和外键约束。
MySQL为什么InnoDB是默认引擎?
- 事务支持:提供了事务支持,可进行ACID操作,而
MyISAM
不支持事务。 - 并发性能:支持行家锁机制,可提供良好的并发性能。
- 崩溃恢复:支持
redolog
日志实现了崩溃恢复,保证了数据的持久性和一致性。
说一下mysql的innodb与MyISAM的区别?
Innodb
:
- 支持事务。
- 采用聚簇索引,文件放在主键索引的叶子节点上,因此Innodb必须要有主键,通过主键索引效率很高。
- 最小细粒度是行级
- count的效率低,因为采用函数不会使用索引而是全表扫描。
MyISAM
:
- 不支持事务
- 采用非聚簇索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
- 最小细粒度是表级锁
- count的效率高
数据管理里,数据文件大体分成哪几种数据文件?
- 以
.opt
结尾的文件:存储数据库的默认字符集和字符校验规则。 - 以
.frm
结尾的文件:存储表结构,用来保存每个表的元数据信息,包括表结构定义。 - 以
.lbd
结尾的文件:存放表数据,既可以存储共享表空间文件,也可存放读者表空间文件。
索引
索引是什么?有什么好处?
索引类似于书的目录,可以提高查询效率
- 如果没有索引直接查询是全表扫描时间复杂度是On
- 如果用到索引,走的是二分查找,通过索引快速定位到目标数据。
讲讲索引的分类是什么?
按数据结构分类
B+tree索引
、Hash索引
、Full+text索引
索引类型 | InnDB | MyISAM | Memory |
---|---|---|---|
B+Tree | ok | ok | ok |
HASH | no | no | ok |
Full-Text | ok(5.6版本后支持) | ok | no |
索引创建规则
- 如果有主键:默认使用主键左右聚簇索引的索引键。
- 没有主键:则选第一个不包含noll的值唯一列作为索引。
- 都没有的情况下:InnDB会自动生成一个隐式自增的id列作为默认的索引键
创建的主键索引和二级索引默认使用B+Tree索引
按物理存储分类
聚簇索引
、二级索引
- 主键索引B+Tree的叶子节点存放实际数据,非叶子节点存放索引
- 二级索引B+Tre的叶子节点存放主键值。
如果查询数据用到了二级索引,如果数据在二级索引里面能查询到,直接返回—这就是覆盖索引。
如果不在二级索引里面,会先检索二级索引,找到对应叶子节点,获取主键值,再检索主键索引—这就是回表。
按字段特性分类
主键索引
、唯一索引
、普通索引
、前缀索引
- 主键索引:建立在主键字段上的索引,一张表最多只能有一个。
- 唯一索引:建立在UNIQUE字段上的索引,一张表可以有多个唯一索引,索引列的值必须唯一。
- 普通索引:建立在普通字段上的索引。
- 前缀索引:对字符类型字段的前几个字符建立的索引,目的是减少索引占用的存储空间,提升查询效率。
按字段个数分类
单列索引
、联合索引
- 单例索引:建立在单列上的索引,比如主键索引。
- 联合索引:通过将多个字段组合成一个索引,该索引就被称为联合索引。
联合索引存在最左匹配原则
,如果不遵遵循最左匹配原则,联合索引会失效。
MySQL聚簇索引和非聚簇索引的区别是什么?
聚簇索引
- 数据存储:索引的叶子节点包含实际的数据行。
- 索引与数据关系:可以直接从索引中获得数据行,而不需要额外的步骤去查找数据所在的位置。
- 唯一性:每个表只能有一个聚簇索引
- 效率:对于范围查询和排序查询,聚簇索引通常更有效率。
非聚簇索引
- 叶子节点不包含完整的数据行,而是包含指向数据行的指针或主键值。
- 首先需要在非聚簇索引找到对应的主键值,然后通过主键值回溯到聚簇索引查找实际是数据行。
- 一个表可以有多个非聚簇索引。
- 叶子节点不包含完整的数据行,而是包含指向数据行的指针或主键值。
如果聚簇索引的数据更新,它的存储要不要变化?
- 如果是非索引数据-普通用户记录,存储结构不会发送变化。
- 如果是索引数据,存储结构是有变化的。
MySQL主键是聚簇索引吗?
在InnDB引擎中,主键是以聚簇索引形式存储的。
什么字段适合当做主键?
- 字段具有唯一性,且不能为空。
- 字段最好具有递增的趋势,如果字段是随机无序可能会引发页分裂,对性能造成影响。
- 不建议使用业务数据作为主键。
- 通常情况下会使用自增字段作为主键,对应分布式系统,就需要考虑分布式id的方案。
Mysql中的索引是怎么实现的 ?
MySQL InnoDB 引擎是用了B+树
作为了索引的数据结构。
B+树:多叉树,叶子节点存放数据,非叶子节点存放索引,而且每个节点的数据是按主键顺序存放的
。每一层父节点的索引值都会出现在下层叶子节点的索引值中。因此在叶子节点包含了所有的索引值信息
。每一个叶子节点都有两个指针,分别指向下一个叶子节点和上一个叶子节点,形成双向链表
。
B+Tree相比于B树和二叉树来说,最大的优势在与查询效率很高,在庞大的数据量的情况下,查询一个数据的磁盘I/O依然维持在3~4次.
B+树的特性是什么?
- 所有叶子节点都在同一层:确保了所有数据项的检索具有相同的I/O延迟,提高搜索效率。B+树非常适合进行范围查询和排序扫描。可以沿着叶子节点的链表顺序访问数据,而无需进行多次随机访问。
- 非叶子节点存储键值:仅存储键值和指向子节点的指针,不包含数据记录。由于非叶子接待你只存方键值,在数据量大的时候,B+树比B树层高更少。
- 叶子节点存储数据记录:每次搜索都会到达叶子节点。
- 自平衡:B+树在插入、删除和更新操作后会自动重新平衡,确保树的高度保持相对稳定,从而保持良好的搜索性能
说说B+树和B树的区别
- B+树,数据都存储在叶子节点,而非叶子节点只存储索引信息。B树,非叶子节点即存储索引信息又存储数据。
- B+树,叶子节点由链表相联,便于范围查询和顺序方法,而B树无。
- B+树查找性能更稳定,因为每次都需要查找到叶子节点,而B树查找可能在非叶子节点,性能相对不稳定。
B+树的好处是什么?
B+树的非叶子节点不存放实际数据,仅存放索引,因此在数据量相同的情况下,相比B树,树更加
矮胖
,查询底层节点的磁盘I/O次数更少B树有大量冗余节点(所有非叶子节点都是冗余节点),这会让B+树在插入、删除效率更高。
B+树叶子节点用链表连接起来,有利于范围查询。
B+树的叶子节点链表是单向还是双向?
双向的->实现倒叙遍历或排序
MySQL为什么用B+树结构?和其他结构比的优点?
- B+Tree VS B Tree:B+Tree只在叶子节点存放数据,而B+Tree叶子节点和非叶子节点都要存放数据,所以树更加矮,在相同的磁盘I/O次数下,能查询到更多节点。B+树叶子节点采用双向链表,适合范围查询。
- B+ Tree VS Hash:Hash在做等值查询的时候效率高,但Hash表不适合做范围查询。
为什么 MySQL 不用 跳表?
B+Tree的高度在3层的情况下可能达到千万级。但对应调表区维护千万数据量所造成的调表层数过高会造成磁盘io次数过多。
B+树在存储相同数据磁盘io次数更少。
创建联合索引时需要注意什么?
建立联合索引时的字段顺序索引效率有很大影响。越靠前的字段被用于索引过滤的概览越高。
建立联合索引时,要把区分度大的字段拍照前面,这样区分度大的字段越有可能被更多的SQL使用。
索引失效有哪些?
- 使用左或者左右模糊匹配:比如 like %xx或者like %xx%。
- 查询条件中使用函数
- 查询条件中对索引列使用表达式计算
- MySQL在遇到字符串和数字表达式比较的时候,会把字符串自动转为数字进行比较。如果字符串是索引列,而条件语句中的输入参数是数字,索引列会发生隐士类型转换。用到函数造成索引失效。
- 联合索引时要遵循最左匹配原则
- 在where字句中,如果or前的条件列是索引列,or后的条件不是索引列。
什么情况下会回表查询
如果查询的数据不在二级索引中,就会先检索二级索引,找到对应的叶子节点,获取主键值。然后再检索主键索引,就能够查询到数据了—这个过程就是回表。
什么是覆盖索引?
查询所需的所有数据都能从索引直接获取,而不需要进行回表查询。覆盖索引能够显著提高查询性能,因为减少了访问数据也的次数,从而减少了I/O操作。
索引已经建好了,那我再插入一条数据,索引会有哪些变化?
插入新数据可能导致B+树结构的调整和索引信息的变化。
如果插入的数据导致叶子节点已满,可能会触发叶子节点的分裂操作。
索引字段是不是建的越多越好?
不是,建的越多消耗的空间越多,在频繁写入场景下,维护B+树所付出的性能消耗也会大。
如果有一个字段是status值为0或者1,适合建索引吗
不适合,区分度低。
索引的优缺点?
优点:
- 提高查询速度
缺点
- 需要占用物理空间,数量越大,占用空间越大。
- 创建索引和维护索引需要消耗时间。
- 会降低表的增删改效率,因为每次增删改索引,B+树为了维护索引有序性,需要进行动态平衡。
怎么决定建立哪些索引?
什么时候使用索引?
- 字段有唯一性限制。
- 经常用于
where
查询条件的字段。 - 经常用于
group by
和order by
的字段。
什么时候不需要创建索引?
whrer
条件,group by
,order by
用不到的字段。- 字段中存放大量重复数据,不需要创建索引。
- 表数据太少。
- 经常更新的字段。
索引优化详细讲讲
- 前缀优化法:使用前缀索引目的是减少索引字段大小,增加一个索引页存储的索引值,有效提高索引查询速度。
- 覆盖索引优化:覆盖索引是指SQL的query的所有字段,在索引B+tree的叶子节点上都能找到那些索引,从二级索引中查询得到记录,而不需要从聚簇索引查询获得,避免回表。
- 主键索引最好是自增的
- 如果使用自增主键,每次插入新数据就会按照顺序添加到当前索引节点位置,不需要移动已有的数据,当页面写满,就会自动开辟一个新的页面。插入一条心记录,都是追加操作,不需要重新移动数据,插入数据方法效率非常高。
- 如果使用非递增主键,每次插入主键都是随机的,因此每次插入新的数据是,就可能会插入到现有数据页的某个中间位置,这需要移动其它数据来满足新数据的插入。甚至需要从一个页面复制数据到另外一个页面,这就是
页分裂
这回导致大量的内存碎片,从而影响查询效率。
- 防止索引失效。
事务
事务的特性是什么?如何实现的?
原子性
:一个事务中所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节,而且事务在执行过程中发生错误,会被回滚到事务开始前的状态。一致性
:事务操作前和操作后,数据满足完整性约束和,数据库保持一致性。隔离性
:数据库允许多个并发事务 同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行由于交叉执行而导致数据的不一致。持久性
:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
InnDB通过什么技术保持事务的这四个特性?
原子性
:undo log(回滚日志)一致性
:持久性+隔离性+原子性来保持的。隔离性
:通过MVCC(多版本并发控制)或锁机制保证的。持久性
: redo log(重做日志)
mysql可能出现什么和并发相关问题?
可能会出现
脏读
,不可重复读
, 幻读
等问题。
脏读
如果一个事务「读到」了另一个「未提交事务修改过的数据」,就意味着发生了「脏读」现象。
不可重复读
在一个事务内多次读取同一个数据,如果出现前后两次读到的数据不一样的情况,就意味着发生了[不可重复读]现象
幻读
在一个事务内多次查询某个符合查询条件的[记录数量],如果出现前后两次查询到的记录不一样的情况,就意味着发生了[幻读]现象。
发现和前一次读到的记录数量不一样,就感觉发生了幻觉一样,这种现象就被称为幻读。
哪些场景不适合脏读,举个例子?
脏读:一个事务读取到另外一个事务未提交的数据时发生。
不适合的场景
- 银行系统
- 库存管理系统
- 在线订单系统
mysql的是怎么解决并发问题的?
- 锁机制:MySQL提供了多种锁机制保证数据的一致性,包括行级锁,表级锁,页级锁等。通过锁机制,可以在读写操作时对数据库加锁,确保同时只有一个操作能够访问或修改数据。
- 事务隔离级别:MySQL通过设置多种事务隔离级别,包括读为提交,读已提交,可重复读和串行化。通过设置合适的事务隔离级别,可以在多个事务并发执行时,控制事务之间的隔离程度,避免数据不一致问题。
- MVCC机制:MySQL使用MVCC来管理并发访问,它通过在数据库中保存不同版本的数据来实现不同事务之间的隔离。在读取数据时,MySQL会根据事务的隔离级别来选择合适的数据版本,从而保证数据的一致性。
事务的隔离级别有哪些?
读未提交
:指一个事务还未提交时,它做的变更就能被其它事务看到。读提交
:指一个事务提交之后,它做的变更才能被其它事务看到。可重复读
:指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据一致,MySQL InnoDB引擎的默认隔离级别。串行化
:对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突时。后续的事务必须等待前一个事务执行完成,才能继续执行。
隔离水平:
串行化 > 可重复读 > 读已提交 > 读未提交
读未提交:脏读、不可重复读和幻读。
读已提交:不可重复读和幻读。
可重复读:幻读
四种隔离级别具体是如何实现的呢?
- 读未提交:直接读取最新数据。
- 串行化:加读写锁。
- 读提交和可重复读:通过Read View实现,区别是创建Read View的时机不同。
读提交
是在每个语句执行前都会重新生成一个Read View,而可重复读
是在启动事务时生成一个Read View,然后整个事务期间都在用这个Read View。
Mysql 设置了可重读隔离级后,怎么保证不发生幻读?
尽量在开启事务之后,马上执行 select … for update 这类锁定锁的语句,因为它会对记录加 next -key lock ,从而避免其它事务插入一条新纪录,就避免了幻读问题。
介绍MVCC实现原理
对于「读提交」和「可重复读」隔离级别的事务来说,它们是通过 Read View 来实现的,它们的区别在于创建 Read View 的时机不同,大家可以把 Read View 理解成一个数据快照,就像相机拍照那样,定格某一时刻的风景。
- 「读提交」隔离级别是在「每个select语句执行前」都会重新生成一个 Read View;
- 「可重复读」隔离级别是执行第一条select时,生成一个 Read View,然后整个事务期间都在用这个 Read View。
这种通过「版本链」来控制并发事务访问同一个记录时的行为就叫 MVCC(多版本并发控制)。
一条update是不是原子性的?为什么?
是原子性的,主要通过锁+undolog日志保证原子性。
- 执行update时, 会加行级锁,保证一个事务更新一条记录时,不会被其它事务干扰。
- 事务执行过程中,会生成 undolog,如果事务执行失败,就可以通过 undolog 日志进行回滚。
滥用事务,或者一个事务里有特别多sql的弊端?
- 如果一个事务特别多 sql,锁定的数据太多,容易造成大量的死锁和锁超时。
- 回滚记录会占用大量存储空间,事务回滚时间长。sql 越多,所需要保存的回滚数据就越多。
- 执行时间长,容易造成主从延迟,主库上必须等事务执行完成才会写入binlog,再传给备库。
锁
讲一下mysql里有哪些锁
分为全局锁、表级锁和行锁
全局锁
通过flush tables with read lock 语句会将整个数据库就处于只读状态了,这时其他线程执行以下操作,增删改或者表结构修改都会阻塞。全局锁主要应用于做全库逻辑备份,这样在备份数据库期间,不会因为数据或表结构的更新,而出现备份文件的数据与预期的不一样。
表级锁
- 表锁:lock tables 语句可以对表加表锁,表锁除了会限制别的线程的读写外,也会限制本线程接下来的读写操作。
- 元数据锁:当我们对数据库表进行操作时,会自动给这个表加上 MDL,对一张表进行 CRUD 操作时,加的是 MDL 读锁;对一张表做结构变更操作的时候,加的是 MDL 写锁;MDL 是为了保证当用户对表执行 CRUD 操作时,防止其他线程对这个表结构做了变更。
- 意向锁:当执行插入、更新、删除操作,需要先对表加上「意向独占锁」,然后对该记录加独占锁。意向锁的目的是为了快速判断表里是否有记录被加锁。
行级锁
- 记录锁,锁住的是一条记录。而且记录锁是有 S 锁和 X 锁之分的,满足读写互斥,写写互斥
- 间隙锁,只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。
- Next-Key Lock 称为临键锁,是 Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。
数据库的表锁和行锁有什么作用?
表锁
- 整体控制:用来控制整个表的并发访问,当一个事务获取表锁时,其它事务无法对该表进行任务读写操作,保证数据的完整性和一致性。
- 粒度大:表锁的粒度比较大,在锁定表的情况下,可能会影响到整个表的其他操作,可能会引起锁竞争和性能问题。
- 适用于大批量操作:表锁适合于需要大批量操作表中数据的场景
行锁
- 细粒度控制:可以精确控制对表中某行数据的访问,在并发量大的系统中能够提高并发性能。
- 减少锁冲突:行锁不会像表锁那样造成整个表的锁冲突,减少了锁竞争的可能性,提高了并发访问的效率。
- 适用于频繁单行操作:行锁适合于需要频繁对表中单独行进行操作的场景,例如订单系统中的订单修改、删除等操作。
如果2个范围不是主键或索引?还会阻塞吗?
如果2个范围查询的字段不是索引的话,那就代表 update 没有用到索引,这时候触发了全表扫描,全部索引都会加行级锁,这时候第二条 update 执行的时候,就会阻塞了。
因为如果 update 没有用到索引,在扫描过程中会对索引加锁,所以全表扫描的场景下,所有记录都会被加锁,相当于锁住了全表。
日志
日志文件是分成了哪几种?
- redo log 重做日志:是 Innodb 存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复;
- undo log 回滚日志:是 Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和 MVCC。
- bin log 二进制日志:是 Server 层生成的日志,主要用于数据备份和主从复制;
讲一下binlog
MySQL 在每次完成一条更新操作后,Server层就会生成一条binlog,等事务提交后,会将事务执行过程中产生的所有binlog统一写入binlog文件。
binlog是追加写 , 写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志。
binlog 文件记录了所有数据库表结构和表数据修改的日志,不会记录查询类的操作。
binlog 有 3 种格式类型
STATEMENT
每一条修改数据的 SQL 都会被记录到 binlog 中。
但 STATEMENT 有动态函数的问题,比如你用了 uuid 或者 now 这些函数,你在主库上执行的结果并不是你在从库执行的结果,这种随时在变的函数会导致复制的数据不一致;
ROW
记录行数据最终被修改成什么样了。
不会出现 STATEMENT 下动态函数的问题。但 ROW 的缺点是每行数据的变化结果都会被记录,比如执行批量 update 语句,更新多少行数据就会产生多少条记录,使 binlog 文件过大,而在 STATEMENT 格式下只会记录一个 update 语句而已;
MIXED
包含了 STATEMENT 和 ROW 模式,它会根据不同的情况自动使用 ROW 模式和 STATEMENT 模式
UndoLog日志的作用是什么?
undo log 是一种用于撤销回退的日志,它保证了事务的 ACID 特性中的原子性
在事务没提交之前,MySQL 会先记录更新前的数据到 undo log 日志文件里面,当事务回滚时,可以利用 undo log 来进行回滚。
每当 InnoDB 引擎对一条记录进行操作(修改、删除、新增)时,要把回滚时需要的信息都记录到 undo log 里,比如:
- 在插入一条记录时,要把这条记录的主键值记下来,这样之后回滚时只需要把这个主键值对应的记录删掉就好了;
- 在删除一条记录时,要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了;
- 在更新一条记录时,要把被更新的列的旧值记下来,这样之后回滚时再把这些列更新为旧值就好了。
有了undolog为啥还需要redolog呢?
Buffer Pool 是基于内存的,而内存总是不可靠,万一断电重启,还没来得及落盘的脏页数据就会丢失。
为了防止断电导致数据丢失的问题,当有一条记录需要更新的时候,InnoDB 引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以 redo log 的形式记录下来,这个时候更新就算完成了。
后续,InnoDB 引擎会在适当的时候,由后台线程将缓存在 Buffer Pool 的脏页刷新到磁盘里,这就是 WAL (Write-Ahead Logging)技术。
WAL 技术指的是, MySQL 的写操作并不是立刻写到磁盘上,而是先写日志,然后在合适的时间再写到磁盘上。