首页 > Mysql高频面试题汇总
头像
已加入本公司人才库
编辑于 2021-08-05 14:45
+ 关注

Mysql高频面试题汇总

问题来源于多篇面经,答案都是自己手动收集整理的,有任何错漏之处欢迎指正~


数据库的三大范式 ?有什么用?

范式是符合某一种设计要求的总结。要想设计一个冗余较小、结构合理的关系型数据库,必须满足一定的范式。
1.第一范式:表中每一列不可分解
例如家庭住址这个属性应该被拆分成:所在省、所在市、所在区县、具体地址,便于后续按照省市进行检索
2.第二范式:确保每个字段都和主键相关
订单表:订单id,商品id,商品名,发货数量
主键是订单id,其中的商品名只和商品id有关,和主键订单id无关,因此要将订单表拆分出一个商品详情表
3.第三范式:确保每列都和主键列直接相关,而不是间接相关
订单表:订单id,商品id,用户名,用户电话
用户名和用户电话和订单id间接相关,而不是直接相关。应该拆分出一个用户表描述用户详细信息,在订单表中只保留用户id
(订单表中只有客户编号,没有客户其他信息,保证客户信息不重复出现)

范式的优点:因为相对来说有较少的重复数据,范式化的更新操作要比反范式快。同时范式化需要更少的distinct和order by
范式化缺点:通常需要关联,不仅代价昂贵,也可能会使的一些索引无效


关系型数据库和非关系型数据库的区别

关系型:把复杂的关系归结为二元关系,即二维表格形式,例如MySQL(数据库-表-行-列)

非关系型:一般以简单的key-value模式存储,因此大大增加了数据库的扩展能力,不支持ACID,远超于SQL的性能。
键值对缓存形式(Redis),文档形式(索引-类型-文档-字段)(Elasticsearch)
适用场景:
对数据高并发的读写(mysql数据库存储在磁盘上,高并发会产生大量IO)
对海量数据的读写(mysql数据库不支持海量数据)
对数据高可扩展性的(例如key-value,redis中支持5种类型的value)




mysql的数据类型

整型:
TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT 分别使用 8, 16, 24, 32, 64 位存储空间,一般情况下越小的列越好。
INT(11) 中的数字只是规定了交互工具显示字符的个数,对于存储和计算来说是没有意义的。

浮点数:
FLOAT 和 DOUBLE 为浮点类型,DECIMAL 为高精度小数类型。CPU 原生支持浮点运算,但是不支持 DECIMAl 类型的计算,因此 DECIMAL 的计算比浮点类型需要更高的代价。
FLOAT、DOUBLE 和 DECIMAL 都可以指定列宽,例如 DECIMAL(18, 9) 表示总共 18 位,取 9 位存储小数部分,剩下 9 位存储整数部分。

字符串
主要有 CHAR 和 VARCHAR 两种类型,一种是定长的,一种是变长的。
VARCHAR 这种变长类型能够节省空间,因为只需要存储必要的内容。但是在执行 UPDATE 时可能会使行变得比原来长,当超出一个页所能容纳的大小时,就要执行额外的操作。MyISAM 会将行拆成不同的片段存储,而 InnoDB 则需要分裂页来使行放进页内。
在进行存储和检索时,会保留 VARCHAR 末尾的空格,而会删除 CHAR 末尾的空格。
char比varchar的优势?

时间和日期
MySQL 提供了两种相似的日期时间类型:DATETIME 和 TIMESTAMP
1. DATETIME
能够保存从 1000 年到 9999 年的日期和时间,精度为秒,使用 8 字节的存储空间。
它与时区无关。
默认情况下,MySQL 以一种可排序的、无歧义的格式显示 DATETIME 值,例如“2008-01-16 22<span>:</span>37<span>:</span>08”,这是 ANSI 标准定义的日期和时间表示方法。

2. TIMESTAMP
和 UNIX 时间戳相同,保存从 1970 年 1 月 1 日午夜(格林威治时间)以来的秒数,使用 4 个字节,只能表示从 1970 年到 2038 年。
它和时区有关,也就是说一个时间戳在不同的时区所代表的具体时间是不同的。
MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提供了 UNIX_TIMESTAMP() 函数把日期转换为 UNIX 时间戳。
默认情况下,如果插入时没有指定 TIMESTAMP 列的值,会将这个值设置为当前时间。
应该尽量使用 TIMESTAMP,因为它比 DATETIME 空间效率更高




MySQL有哪些日志?分别有什么作用?


1:重做日志(redo log)
确保事务的持久性。redo日志记录事务执行后的状态,用来恢复未写入data file的已成功事务更新的数据。如果在发生故障的时间 点,尚有脏页未写入磁盘,则在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。
是物理格式的日志,记录的是物理数据页面的修改的信息(记录具体是多少),redo log顺序写入redo log file的物理文件中
事务开始之后就产生redo log,随着事务的进行逐步写入日志。事务的脏页写入磁盘后,任务完成,redo log日志就可以被覆盖了。
redolog在引擎层,只有innoDB才有redolog

2:回滚日志(undo log)
保证数据的原子性,保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非 锁定读。
逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不 同于redo log的。
创建时间:事务开始之前,将当前的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性
销毁时间:没有事务使用上一个版本的信息时。

3:二进制日志(binlog)
用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。用于数据库的基于时间点的还原。
主从复制:1.从库是主库的备份,主库故障时可以切换到从库继续工作,避免数据丢失。
2.主库写,从库读,避免单机的io压力。也可以一写多读,合理配置资源(疫情信息很多人查询,但是只有官方写)
binlog记录了所有对主库的修改,将主库的binlog拿到从库,从库的relay-log重做日志文件中再执行一次这些sql语句即可。
binlog中记录了所有sql语句,还额外记录了增删改的反向操作语句(删记录对应的插入,插入记录对应的删,改记录改之前的)
时间:事务提交的时候产生对应的binlog,超过expire_logs_days配置的天数之后自动删除。
binlog和redolog的不同:
1.作用不同:redolog在事务层面保证持久性,是innoDB独有的,binlog在数据库层面起到还原的作用,所有引擎都有。
2.内容不同:redolog存储的是物理日志,记录的是“在某个数据页上做了什么修改”。binlog可以简单认为存储的是sql语句。
3.周期不同:redolog是循环覆盖,新的会覆盖旧的,总大小固定。binlog是追加写入,不会覆盖之前的。

4:错误日志(errorlog)
记录数据库运行过程中发生的错误,默认关闭。

5:慢查询日志(slow query log)
记录执行时间过长和没有使用索引的查询语句,只会记录查询成功的语句。

6:一般查询日志(general log)
记录所有查询语句或者命令,无论是否生效,或者包含语法错误,都会记录。由于有着不小的开销,因此默认关闭

7:中继日志(relay log)。



MySQL默认引擎是?MyISAM和InnoDB的区别?

5.5之前,默认的存储引擎是MyISAM
MyISAM虽然性能极佳,⽽且提供了⼤量的特性,包括全⽂索引、压缩、空间函数等,但MyISAM不⽀持事务和⾏级锁,⽽且最⼤的缺陷 就是崩溃后无法安全恢复。
5.5之后,默认的存储引擎是InnoDB(事务性)

⼤多数时候我们使⽤的都是 InnoDB 存储引擎,但是在某些情况下使⽤ MyISAM 也是合适的。⽐如读密集的情况下。(如果你不介意 MyISAM 崩溃恢复问题的话)。
两者的对⽐:
1. 是否⽀持⾏级锁 : MyISAM 只有表级锁(table-level locking),⽽InnoDB ⽀持⾏级锁(row-level locking)和表级锁,默认为⾏级锁。

2. 是否⽀持事务和崩溃后的安全恢复: MyISAM 强调的是性能,每次查询具有原⼦性,其执⾏速度⽐InnoDB类型更快,但是不提供事务⽀持。但是InnoDB 提供事务⽀持事务,外部键等⾼级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能⼒(crash recovery
capabilities)的事务安全(transaction-safe (ACID compliant))型表。

3. 是否⽀持外键: MyISAM不⽀持,⽽InnoDB⽀持。

4. 是否⽀持MVCC :仅 InnoDB ⽀持。应对⾼并发事务, MVCC⽐单纯的加锁更⾼效;MVCC只在 READ COMMITTED 和 REPEA TABLE READ 两个隔离级别下⼯作;MVCC可以使⽤ 乐观(optimistic)锁 和 悲观(pessimistic)锁来实现;各数据库中MVCC实现并不统⼀。

5.是否支持全文索引:innoDB不支持,MyISAM支持。



select count(*) from tablename 时InnoDB和MylSAM分别是怎么处理的?

select count(*) from tablename 是获取表长的操作。
myisam更快,因为myisam内部维护了一个计数器,可以直接调取。


索引是什么?优缺点?原理?

优点:
提高查询速度
确保数据的唯一性
可以加速表和表之间的连接 , 实现表与表之间的参照完整性
使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间
全文检索字段进行搜索优化

缺点:
创建索引是会产生索引文件的,占用磁盘空间
对于需要写入数据的操作,比如DELETE、UPDATE以及INSERT操作,索引会降低它们的速度。这是因为MySQL不仅要把改动数据写入数据文件,而且它还要把这些改动写入索引文件。

原理:
在我们添加完索引之后,mysql一般通过BTREE算法生成一个索引文件,在查询数据库时,找到索引文件进行遍历(折半查找大幅查询效率),找到相应的键从而获取数据


主键索引与唯一索引的区别

1. 主键是一种约束,唯一索引是一种索引,两者在本质上是不同的。
2. 主键创建后一定包含一个唯一性索引,唯一性索引并不一定就是主键。
3. 唯一性索引列允许空值,而主键列不允许为空值。
4. 主键列在创建时,已经默认为空值 ++    唯一索引了。
5. 一个表最多只能创建一个主键,但可以创建多个唯一索引。
6. 主键更适合那些不容易更改的唯一标识,如自动递增列、身份证号等。
7. 主键可以被其他表引用为外键,而唯一索引不能。


在哪些列上创建索引?

1.经常作为查询条件的字段。不会出现在where子句中的字段不该创建索引

2.唯一性强的字段。例如学号。唯一性太差的字段不适合创建索引,例如gender性别字段

3.更新非常频繁的字段不适合作为索引,因为对该列进行增删改的时候,都会先修改这一列的索引
若是增,则在这一列的索引内以新填入的这个字段名的值为名创建索引的子集,
若是改,则会把原来的删掉,再添入一个以这个字段名的新值为名创建索引的子集,
若是删,则会把索引中以这个字段为名的索引的子集删掉。

4.为经常需要排序、分组和联合操作的字段建立索引
经常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作开销较大。为其建立索引,可以有效地避免排序操作。

5.尽量使用数据量少的索引。如果索引的值很长,那么查询的速度会受到影响。
例如,对一个CHAR(100)类型的字段进行全文检索需要的时间肯定要比对CHAR(10)类型的字段需要的时间要多。


最左匹配原则


在联合索引中,如果SQL 语句中用到了联合索引中的最左边为起点的索引,那么这条 SQL 语句就可以利用联合索引去进行匹配,你可以利用最左匹配原则定义一个联合索引,使得多种查询条件都可以用到该索引。
底层原理:
索引的底层是b+树,比如(name,age,sex)的时候,b+树是按照从左到右的顺序索引列来建立搜索树的,因此查询条件的顺序要满足一定条件才会用到联合索引。
哪些情况下会用到联合索引?

1.全值匹配(查询条件为表中每个字段):select * from table_name where a = '1' and b = '2' and c = '3';
abc cba bac都不会影响结果,因为优化器会调整顺序。
没有从a开始,则全表搜索。

2.前缀、中缀、后缀:select * from table_name where a like 'a%' ('%a%', '%a')
前缀走索引,中缀后缀全表。

3.范围匹配
1. select * from table_name where  a > 1 and a < 3 and b > 1;
多个列进行范围匹配时,只有包含对索引最左边列的范围查找时才走索引。
此时找到a在1,3范围内的所有行,然后逐条判断b的条件
2. select * from table_name where  a = 1 and b > 3;
左边精确右边范围,由于a是索引首列,在a确定的情况下,第二列b是有序的,因此可以走索引。

4.排序
1. select * from table_name order by a,b,c limit 10;
order子句用到了索引列,且order的顺序与索引列的顺序相同,则走索引。order顺序从索引左列开始,也可以用到部分索引。
2. select * from table_name order by b,c,a limit 10;
order顺序与索引顺序不同,用不了索引。

联合索引失效的情况?

1.在索引列上进行计算、函数、自动或者手动类型转换
2.is null, is not null
3.以通配符开头(%a)
4.使用or连接



MySQL索引结构有哪些?为什么用b+树,不用二叉搜索树、平衡二叉树、红黑树、b树(b-树)

二叉搜索树:索引有序插入时树为线性,导致查找性能退化为on。

平衡二叉树:通过平衡因子保持平衡,但是维护平衡的代价比较高。

红黑树:通过自旋保持平衡,效率比平衡二叉树高。
每个节点只能存一个数据,每个节点最多只有两个孩子,导致高度变高,IO频繁
B+树相比红黑树的优点:
1.树高更低

B树:节点可以存多个数据,有多个孩子,层数少,io效率高。


B+树相比B树的优点:
1、 B+树的磁盘读写代价更低:B+树的非叶子节点只存索引不存具体的数据,因此节点更小,一次性读入内存的可以查找的关键字也就越多,相对IO读写次数就降低了。
2、B+树的查询效率更加稳定:所有查找只有到达叶子时才会命中
3、B+树的叶子都串在一起,顺序遍历和范围查找时更方便。而B树只能通过中序遍历。



事务是什么?ACID4大特性?

事务指的是满足 ACID 特性的一组操作。

1.原子性(Atomicity)
事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
回滚可以用回滚日志(Undo Log)来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。

2. 一致性(Consistency)
一致读:只能读最近的一个状态
一致写:数据只能基于最近的一个状态改变

3. 隔离性(Isolation)
事务之间应该是隔离的,一个事务不能影响另一个事务。

4.持久性
一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。
系统发生崩溃可以用重做日志(Redo Log)进行恢复,从而实现持久性。与回滚日志记录数据的逻辑修改不同,重做日志记录的是数据页的物理修改。

MySQL的InnoDB引擎保证事务。


MySQL如何保证事务?

1.原子性:
一个事务内容是从A账户转100到B账户,A-100,B+100,如果完成了第一条之后系统Crash,A凭空少了100,数据发生异常。
引入undo log保证原子性,这是Mysql的Write-Ahead-Logging机制。
undo log记录数据更改前的版本,先于数据顺序写入磁盘。(undolog io效率高于缓存,因此顺序写入,且内容较少)
通过undo log将发生错误异常或者显示时,执行rollback语句把数据还原到原先的模样。

2.一致性:
undo log+redo log保证事务的一致性

3.隔离性:
锁 + MVCC 用来保证事务的隔离性

4.持久性:
mysql有缓存机制,先写入缓存再写入磁盘,如果突然断电则缓存丢失,可能会导致数据丢失。
因此写入数据时,先记录到redo log中。宕机时可以利用redo log重做事务,恢复到最近的一个版本。
redo log记录的是物理记录(?),提供前滚功能,undo log记录的是每一行的字段具体是多少,提供后滚功能。



事务4种隔离级别,分别解决了什么问题?

如果不考虑隔离性,在并发情况下,可能会引发如下问题:
0.丢失修改:两个事务都对一个字段进行修改,第一个事务修改提交后,第二个事务随后修改提交,将第一个的覆盖。
1.脏读:只一个事务读取到了另一个事务未提交的数据。(a向b转账,b+100,a-100,b+100后读取到了b的状态,但此时交易取消)
2.不可重复读:在一个事务内读取表中某一行数据,多次读取结果不同(一个事务读取到的另外一个事务提交的数据)
脏读是一个事务读取了另一未完成的事务执行过程中的数据
而不可重复读是一个事务执行过程中,另一事务修改了当前事务正在读取的数据。
3.幻读:例如A对表内所有记录进行了修改,此时B事务添加了一条记录,导致了A发现了一条未被修改的记录,像是幻觉一样。

MySQL有4种事务隔离级别,隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能影响越大。
事务隔离级别                    脏读        不可重复读    幻读
读未提交(read-uncommitted)       是        是           是
不可重复读(read-committed)      否           是          是
可重复读(repeatable-read)       否        否             是
串行化(serializable)            否         否            否

1.读未提交:可以读到另一个事务未提交的事务
2.读已提交(不可重复读):不能读到另一个事务未提交的事务,解决了脏读问题,但是存在不可重复读的问题(第二次查询结果不同)
3.可重复读:可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会            更新版本号,是当前读(当前版本)。
4.串行化:串行化会锁表,虽然保证不会出现幻读,但是会导致并发效率低下



MySQL怎么实现四种隔离级别?默认隔离级别?为什么选择这个级别?

通过日志文件,锁和MVCC实现。
默认隔离级别是可重复读(RR)。

1.读未提交:
写时加锁,其他事务不能同时写,但是可以读,导致读到了未提交的中间数据。
没有快照读,只能读最新版本的数据。

2.读已提交:
写数据时加上排它锁,其他事务不能读。避免了读到未提交的数据。
加锁:读数据时加锁,读完后立刻解锁。
不加锁:使用MVCC实现的快照读,每次查询时都去读最新版本快照,当一次查询后快照更新时,导致第二次读的快照变化。

3.可重复读:
写数据时加上排它锁,其他事务不能读。避免了读到未提交的数据。
加锁:读的时候加锁,事务结束后解锁。
不加锁:读的时候使用MVCC实现的快照读,一次事务只使用首次查询的数据版本,解决不可重复读问题,不能解决幻读问题。

4.串行化:
读数据,加表级共享锁
写数据,加表级排他锁


MySQL如何解决幻读的问题?

数据库中的锁:
行级锁:
共享锁(读锁 S):用于读读并发,保证读的时候数据不会被更改。其他事务可加共享锁,不能加排它锁。
排它锁(写锁 X):用于写写并发,保证同一时刻只能被一个事务写。
行级锁中,除了S和S兼容,其他都不兼容。

意向锁(表锁):
意向锁表示当前表上是否有行级锁,不必一行一行遍历。
当我们给一行数据加上共享锁之前,数据库会自动先申请表的意向共享锁(IS锁);
当我们给一行数据加上排他锁之前,数据库会自动先申请表的意向排他锁(IX锁)。
我们要加表级别的X锁,首先判断表上是否有被其他事务加了表锁
如果没有,再检查是否有意向锁,此时直接根据意向锁就能知道这张表是否有行级别的X锁或者S锁,
这时候数据表里面如果存在行级别的X锁或者S锁的,加锁就会失败。

意向锁的主要用途是为了表达某个事务正在锁定一行或者将要锁定一行数据。
e.g:事务A要对一行记录r进行上X锁,那么InnoDB会先申请表的IX锁,再锁定记录r的X锁。
在事务A完成之前,事务B想要来个全表操作,此时直接在表级别的IX就告诉事务B需要等待而不需要在表上判断每一行是否有锁。
意向排它锁存在的价值在于节约InnoDB对于锁的定位和处理性能。另外注意了,除了全表扫描以外意向锁都不会阻塞。


InnoDB中的锁?

表级:意向共享锁(IS锁),意向排他锁(IX锁),自增锁
意向共享锁(IS锁):见上文
意向排他锁(IX锁):见上文
自增锁:某些字段被设置为自增,插入时无法确定插入多少条语句,例如INSERT ... SELECT,则锁表
如果确定插入多少条,则通过轻量级锁赋值(自旋?)

行级:
记录锁(Record Lock):单个行记录上的锁。
间隙锁(Gap Lock):禁止在范围内相邻两行的间隙插入。锁定一个范围,但不包括记录本身。
临键锁(Next-Key Lock):是记录锁和间隙锁的结合。锁定一个范围,包括记录本身。是MySQL的默认行锁。

InnoDB的行锁是通过锁住索引来实现的,如果加锁查询时没有使用索引,会将整个表的聚簇索引锁住,相当于锁住整个表。根据锁定范围不同,行锁可分为:
注意了,如果走唯一索引,那么Next-Key Lock会降级为Record Lock,即仅锁住索引本身,而不是范围。也就是说Next-Key Lock前置条件为事务隔离级别为RR且查询的索引走的非唯一索引、主键索引。

为什么有了MVCC还需要行级锁?

1)当前读:即加锁读。读取记录的最新版本,会加锁保证其他并发事务不能修改当前记录,直至获取锁的事务释放锁。使用当前读的        操作主要包括:显示加锁的读操作与插入、更新、删除等写操作。
2)快照读:即不加锁读。读取记录的快照版本而非最新版本,通过MVCC实现。InooDB在可重复读隔离级别下,如果不显示的加LOCK IN SHARE MODE、FOR UPDATE的SELECT操作都属于快照读,保证事务执行过程中只有第一次读之前提交的修改和自己的修改可见,其他的均不可见。
综上可知,通过MVCC可以解决脏读、不可重复读、幻读这些读一致性问题,但是这只是解决了普通SELECTD的数据读取问题,即快照读的读取问题。在当前读,即加锁读的情况下依然要解决脏读、不可重复读、幻读问题。这个时候需要在读取的记录上加锁,由于都是在行记录上加锁,这些锁都称为行级锁。


乐观锁
认为并发现象不那么严重,读取数据后对数据进行修改时,比较版本号,当发现数据被修改时重新读取(版本号和CAS实现)
update table set x = 1, version = #{version} where id = #{id} and version = #{version}

悲观锁
认为并发现象严重,读取数据后加锁。这会导致并发性能下降,适用于写多读少的情况。
select * from table for update(写锁,排他锁) 必须要在事务中才可以起作用



MVCC多版本并发控制是什么?底层实现?

MVCC(多版本并发控制)可以提高并发性能。
早期数据库系统只有读读之间可以并发,读写,写写都要阻塞。
引入MVCC后,可以并行读写,解决不可重复读问题。

MVCC只在 读已提交 和 可重复读 两个隔离级别下工作。
其他两个隔离级别够和MVCC不兼容。
因为 读未提交 总是读取最新的数据行, 而不是符合当前事务版本的数据行。而 串行化 则会对所有读取的行都加锁。

读已提交:MVCC每次读最新版本,导致不可重复读问题
可重复读:MVCC每次读第一次读的版本,实现可重复读。
幻读:MVCC实现可重复读,间隙锁锁定行和内容。

MVCC主要基于以下技术和数据结构实现:

1.隐藏列:
InnoDB中每行数据都有隐藏列,隐藏列中包含了修改本行数据的事务id、指向undo log的指针等。
1.事务id(trx_id):记录修改当前行的事务id
2.回滚指针(roll_pointer):记录修改当前行的undo log地址

2.基于undo log的版本链:
隐藏列中包含了指向undo log的指针,而undo log中也指向了更早版本的undo log,从而形成一条版本链。
如果数据库隔离级别为读未提交,那么读取版本链中最新的数据即可;
如果数据库隔离级别为可串行化,事务之间是串行执行的,不会发生数据不一致的情况,直接执行读操作即可;
如果数据库隔离级别为读已提交或可重复读,那么就需要遍历整条版本链,找到trx_id与当前事务相同的记录,即需要判断版本链中哪个版本是当前事务可见的。InnoDB通过ReadView实现了这个功能。

3.ReadView:
通过隐藏列和版本链,MySQL可以读取历史版本的数据;但是具体是哪个版本,则需要根据ReadView来确定。
ReadView 结构,主要包含了当前系统未提交的事务列表,还有该列表的最小值(最久未提交)和最大值(最新未提交)。
在进行 SELECT 操作时,根据数据行快照的事务id与列表中的最小值和最大值之间的关系,从而判断数据行快照是否可以使用:
TRX_ID < TRX_ID_MIN,表示该数据行快照时在当前所有未提交事务之前进行更改的,因此可以使用。
TRX_ID > TRX_ID_MAX,表示该数据行快照是在事务启动之后被更改的,因此不可使用。
TRX_ID_MIN <= TRX_ID <= TRX_ID_MAX,需要根据隔离级别再进行判断:
提交读:如果 TRX_ID 在 TRX_IDs 列表中,表示该数据行快照对应的事务还未提交,则该快照不可使用。否则表示已经提交,可以使用。
可重复读:都不可以使用。因为如果可以使用的话,那么其它事务也可以读到这个数据行快照并进行修改,那么当前事务再去读这个数据行得到的值就会发生改变,也就是出现了不可重复读问题。
在数据行快照不可使用的情况下,需要沿着 Undo Log 的回滚指针 ROLL_PTR 找到下一个快照,再进行上面的判断。

全部评论

(2) 回帖
加载中...
话题 回帖

推荐话题

相关热帖

热门推荐