一、数据库基础
1、MySQL 有哪些数据库类型?
(1) 整数类型:
TINYINT 1 字节
SMALLINT 2 字节
MEDIUMINT 3 字节
INT 4 字节
BIGINT 8 字节
① 任何整数类型都可以加上 UNSIGNED 属性,
表示无符号整数
② 任何整数类型都可以指定长度,但它不会限
制数据的合法长度,仅仅限制了显示长度
(2) 小数类型:
FLOAT
DOUBLE
DECIMAL
(3) 字符串类型:
VARCHAR
CHAR
TEXT
BLOB
注意:VARCHAR(n) 和 CHAR(n) 中的 n 并
不代表字节个数,而是代表字符的个数
(4) 日期和时间类型
DATETIME
DATE
TIMESTAMP
尽量使用 TIMESTAMP,空间效率高于 DATETIME
2、CHAR 和 VARCHAR 区别?
(1) CHAR 是定长的,而 VARCHAR 是可以变长
CHAR 会根据声明的字符串长度分配空间,并
会使用空格对字符串右边进行尾部填充,所以
在检索 CHAR 类型数据时尾部空格会被删除,
如保存的是字符串 'char ',但最后查询到的是
'char';又因为长度固定,所以存储效率高于
VARCHAR 类型
VARCHAR 在 MySQL 5.0 之后长度支持到
65535 字节,但会在数据开头使用额外 1~2 个
字节存储字符串长度(列长度小于 255 字节时
使用 1 字节表示,否则 2 字节),在结尾使用
1 字节表示字符串结束
(2) 在存储方式上,CHAR 对英文字符(ASCII)占用
1 字节,对一个汉字使用用 2 字节
而 VARCHAR 对每个字符均使用 2 字节
虽然 VARCHAR 是根据字符串长度分配存储空
间的,但在内存中依旧使用声明长度进行排序
等作业,故在使用时仍需综合考量字段长度
3、CHAR 和 VARCHAR 如何选择?
① 对于经常变更的数据来说,CHAR 比
VARCHAR 更好,因为 CHAR 不容易产生
碎片
② 对于非常短的列或固定长度的数据 (如 MD5),
CHAR 比 VARCHAR 在存储空间上更有效率
③ 使用时要注意只分配需要的空间,更长的列
排序时会消耗更多内存
④ 尽量避免使用 TEXT/BLOB 类型,查询时会
使用临时表,导致严重的性能开销
4、CHAR,VARCHAR 和 Text 的区别?
1)长度区别
Char 范围是 0~255
Varchar 最长是 64k
Text,最大能到 4G
2)效率区别
效率来说基本是 Char > Varchar > Text,但是
如果使用的是 Innodb 引擎的话,推荐使用
Varchar 代替 Char
3)默认值区别
Char 和 Varchar 支持设置默认值,而 Text 不能
指定默认值
二、 数据库设计
1、什么是三大范式?
第一范式 (1NF):字段(或属性)是不可分割的最
小单元,即不会有重复的列,体现原子性
第二范式 (2NF):满足 1NF 前提下,存在一个
候选码,非主属性全部依赖该候选码,即存在
主键,体现唯一性,专业术语则是消除部分函
数依赖
第三范式 (3NF):满足 2NF 前提下,非主属性
必须互不依赖,消除传递依赖
2、什么是范式和反范式,以及各自优缺点?
范式是符合某一种级别的关系模式的集合;
构造数据库必须遵循一定的规则,在关系数据
库中,这种规则就是范式
范式优缺点
优点:范式化的表减少了数据冗余,数据表更
新操作快、占用存储空间少
缺点:查询时通常需要多表关联查询,更难进
行索引优化
反范式优缺点
优点:反范式的过程就是通过冗余数据来提高
查询性能,可以减少表关联和更好进行
索引优化
缺点:存在大量冗余数据,并且数据的维护成
本更高
所以在平时工作中,我们通常是将范式和反范式
相互结合使用
三、索引
索引是对数据库表中一列或多列的值进行排序的
数据结构,用于快速访问数据库表中的特定信息
1、索引的几种类型或分类?
1)从物理结构上可以分为聚簇索引和非聚簇索
引两类:
聚簇索引指索引的键值的逻辑顺序与表中相
应行的物理顺序一致,即每张表只能有一个
聚簇索引,也就是我们常说的主键索引;
非聚簇索引的逻辑顺序则与数据行的物理顺
序不一致
2)从应用上可以划分为一下几类:
普通索引:MySQL 中的基本索引类型,没有
什么限制,允许在定义索引的列中插入重复值
和空值,纯粹为了提高查询效率
通过 ALTER TABLE table_name ADD INDEX
index_name (column) 创建;
唯一索引:索引列中的值必须是唯一的,但是
允许为空值。
通过 ALTER TABLE table_name ADD UNIQUE
index_name (column) 创建;
主键索引:特殊的唯一索引,也成聚簇索引,
不允许有空值,并由数据库帮我们自动创建;
组合索引:组合表中多个字段创建的索引,遵
守最左前缀匹配规则;
全文索引:只有在 MyISAM 引擎上才能使用,
同时只支持 CHAR、VARCHAR、TEXT 类型
字段上使用
2、索引的优缺点?
优点:创建索引可以大大提高系统的性能
① 通过创建唯一性索引,可以保证数据库表中
每一行数据的唯一性
② 可以大大加快数据的检索速度,这也是创建
索引的最主要的原因
③ 可以加速表和表之间的连接,特别是在实现
数据的参考完整性方面特别有意义
④ 在使用分组和排序子句进行数据检索时,同
样可以显著减少查询中分组和排序的时间
⑤ 通过使用索引,可以在查询的过程中,使用
优化隐藏器,提高系统的性能
缺点:
① 创建和维护索引需要耗费时间,这种时间随
着数据量的增加而增加,这样就降低了数据
的维护速度
② 索引需要占物理空间,除了数据表占数据空
间之外,每一个索引还要占一定的物理空间
③ 如果要建立聚簇索引,那么需要的空间就会
更大
3、索引设计原则?
① 选择唯一性索引;
唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录
② 为常作为查询条件的字段建立索引;
如果某个字段经常用来做查询条件,那么该字段的查询速度会影响整个表的查询速度
③ 为经常需要排序、分组和联合操作的字段建
立索引;
经常需要 ORDER BY、GROUP BY、DISTINCT和 UNION 等操作的字段,排序操作会浪费很
多时间
④ 限制索引的数目;
每个索引都需要占⽤用磁盘空间,索引越多,需要的磁盘空间就越大,修改表时,对索引的
重构和更新很麻烦
⑤ 小表不建议索引 (如数量级在百万以内)
由于数据较小,查询花费的时间可能比遍历索引的时间还要短,索引可能不会产生优化效果
⑥ 尽量使用数据量少的索引;
如果索引的值很长,那么查询的速度会受到影响,此时尽量使用前缀索引
⑦ 删除不再使用或者很少使用的索引
4、索引的数据结构?
① 索引的数据结构和具体存储引擎的实现有关,
MySQL 中常用的是 Hash 和 B+ 树索引
② Hash 索引底层就是 Hash 表,进行查询时调
用 Hash 函数获取到相应的键值(对应地址),
然后回表查询获得实际数据.
③ B+ 树索引底层实现原理是多路平衡查找树,
对于每一次的查询都是从根节点出发,查询
到叶子节点方可以获得所查键值,最后查询
判断是否需要回表查询.
5、Hash 和 B+ 树索引的区别?
Hash
① Hash 进行等值查询更快,但无法进行范围查
询
因为经过 Hash 函数建立索引之后,索引的顺
序与原顺序无法保持一致,故不能支持范围查
询。同理,也不支持使用索引进行排序
② Hash 不支持模糊查询以及多列索引的最左前
缀匹配,因为 Hash 函数的值不可预测,如 AA
和 AB 的算出的值没有相关性
③ Hash 任何时候都避免不了回表查询数据.
④ 虽然在等值上查询效率高,但性能不稳定,因
为当某个键值存在大量重复时,产生 Hash 碰
撞,此时查询效率反而可能降低
B+ Tree
① B+ 树本质是一棵查找树,自然支持范围查询
和排序
② 在符合某些条件(聚簇索引、覆盖索引等)时候
可以只通过索引完成查询,不需要回表
③ 查询效率比较稳定,因为每次查询都是从根节
点到叶子节点,且为树的高度。
6、为何使用 B+ 树而非二叉查找树做索引?
二叉树的查找效率为 O(logn),当树过高时,查找
效率会下降
另外由于我们的索引文件并不小,所以是存储在磁
盘上的;文件系统需要从磁盘读取数据时,一般以
页为单位进行读取,假设一个页内的数据过少,那
么操作系统就需要读取更多的页,涉及磁盘随机 I/O
访问的次数就更多。将数据从磁盘读入内存涉及随
机 I/O 的访问,是数据库里面成本最高的操作之一
因而这种树高会随数据量增多急剧增加,每次更新
数据又需要通过左旋和右旋维护平衡的二叉树,不
太适合用于存储在磁盘上的索引文件
7、为何使用 B+ 树而非 B 树做索引?
B+ 树和 B 树的区别:
B 树非叶子结点和叶子结点都存储数据,因此查询
数据时,时间复杂度最好为 O(1),最坏为 O(log n)
而 B+ 树只在叶子结点存储数据,非叶子结点存储
关键字,且不同非叶子结点的关键字可能重复,因
此查询数据时,时间复杂度固定为 O(log n)
B+ 树叶子结点之间用链表相互连接,因而只需扫
描叶子结点的链表就可以完成一次遍历操作,B 树
只能通过中序遍历
为什么 B+ 树比 B 树更适合应用于数据库索引?
① B+ 树减少了 IO 次数。
由于索引文件很大因此索引文件存储在磁盘上,B+树的非叶子结点只存关键字不存数据,因而单个页
可以存储更多的关键字,即一次性读入内存的需要
查找的关键字也就越多,磁盘的随机 I/O 读取次数
相对就减少了
② B+ 树查询效率更稳定
由于数据只存在在叶子结点上,所以查找效率固定为 O(log n),所以 B+ 树的查询效率相比B树更加稳
定
③ B+ 树更加适合范围查找
B+ 树叶子结点之间用链表有序连接,所以扫描全部数据只需扫描一遍叶子结点,利于扫库和范围查询;
B 树由于非叶子结点也存数据,所以只能通过中序
遍历按序来扫。也就是说,对于范围查询和有序遍
历而言,B+ 树的效率更高
8、什么是最左匹配原则?
最左优先,以最左边为起点任何连续的索引都能匹
配上,同时遇到范围查询(>、<、between、like)
就会停止匹配
如建立 (a,b,c,d) 索引,查询条件 b = 2 是匹配不到
索引的,但是如果查询条件是 a = 1 and b = 2 或
a=1
又或 b = 2 and a = 1 就可以,因为优化器会自动调
整 a,b 的顺序
再比如 a = 1 and b = 2 and c > 3 and d = 4,其中
d 是用不到索引的,因为 c 是一个范围查询,它之
后的字段会停止匹配
最左匹配的原理
上图可以看出 a 是有顺序的 (1、1、2、2、3、3),
而 b 的值是没有顺序的 (1、2、1、4、1、2) ,所
以 b = 2 这种查询条件无法利用索引
同时我们还可以发现在 a 值相等的情况下 (a = 1),
b 又是顺序排列的,所以最左匹配原则遇上范围查
询就会停止,剩下的字段都无法使用索引
9、什么是覆盖索引?
在 B+ 树的索引中,叶子节点可能存储了当前的键
值,也可能存储了当前的键值以及整行的数据,这
就是聚簇索引和非聚簇索引。 在 InnoDB 中,只有
主键索引是聚簇索引,如果没有主键,则挑选一个
唯一键建立聚簇索引。如果没有唯一键,则隐式的
生成一个键来建立聚簇索引。
当查询使用聚簇索引时,在对应的叶子节点,可以
获取到整行数据,因此不用再次进行回表查询。
10、什么是索引下推?
索引下推 (Index condition pushdown) 简称 ICP,
在 Mysql 5.6 版本上推出的一项用于优化查询的技
术
在不使用索引下推的情况下,在使用非主键索引进
行查询时,存储引擎通过索引检索到数据,然后返
回给 MySQL 服务器,服务器判断数据是否符合条
件
而有了索引下推之后,如果存在某些被索引列的判
断条件时,MySQL 服务器将这一部分判断条件传
递给存储引擎,然后由存储引擎通过判断索引是否
符合 MySQL 服务器传递的条件,只有当索引符合
条件时才会将数据检索出来返回给 MySQL 服务器.
索引条件下推优化可以减少存储引擎查询基础表的
次数,也可以减少 MySQL 服务器从存储引擎接收
数据的次数
四、存储引擎
1、有哪些常见的存储引擎?
① MyISAM:
适用情况:默认的 mysql 插件式存储引擎,应用
以读和插入为主,较少的更新和删除操
作,且对事务的完整性和并发性要求不
高
使用场景:myisam 在 web,数据仓储和其他应用环境下是最常使用的存储引擎之一
② InnoDB:
作用:innodb 可以有效降低删除、更新导致的锁
定;确保事务的完整提交和回滚;用于事务
处理应用程序,支持外键;
适用情况:应用对事务的完整性有比较高的要求,在并发条件下要求事务的一致性,数据
操作除了插入和查询外,还包括很多更
新和删除;
适用场景:类似计费系统或者财务系统等对数据准确性要求较高的系统,选择 innidb 比较
合适
③ MEMORY:
优点:将所有数据保存在 ram 中,在需要快速定
位记录和其他类似数据的环境下,可提供极
快的访问
缺陷:对表的大小有限制,太大的表无法缓存在内存中,其次要确保表的数据可以恢复,数
据库异常终止后表中的数据是可以恢复的
适用情况:memory 表通常用来更新不太频繁的小表,用以快速得到访问效果
④ MERGE:
适用情况:将一系列等同的 myisam 表以逻辑方式
组合在一起,并作为一个对象引用他们
优点:可以突破对单个 myisam 表大小的限制;且通过将不同的表分布在多个磁盘上,可以有
效改善 merge 表的访问效率;
适用场景:诸如数据仓储等 VLDB 环境十分适合
正确选择存储引擎对改善应用的效率可以起到事半功
倍的效果,选择好存储引擎,还需要正确选择表中数
据类型
2、MyISAM 和 InnoDB 的区别?
① InnoDB 支持事务,而 MyISAM 不支持
② InnoDB 支持外键,而 MyISAM 不支持。因此
将一个含有外键的 InnoDB 表转为 MyISAM 表
会失败
③ InnoDB 和 MyISAM 均支持 B+ Tree 数据结构
的索引。但 InnoDB 是聚集索引,而 MyISAM
是非聚集索引
④ InnoDB 不保存表中数据行数,执行 select
count(*) from table 时需要全表扫描
而 MyISAM 用一个变量记录了整个表的行数,
速度相当快 (注意不能有 WHERE 子句)
那为什么 InnoDB 没有使用这样的变量呢?
因为 InnoDB 的事务特性,在同一时刻表中的
行数对于不同的事务而言是不一样的
⑤ InnoDB 支持表、行 (默认) 级锁,而 MyISAM
支持表级锁
InnoDB 的行锁是基于索引实现的,而不是物理
行记录上。即访问如果没有命中索引,则也无
法使用行锁,将要退化为表锁
⑥ InnoDB 必须有唯一索引(如主键),如果没有指
定,就会自动寻找或生产一个隐藏列 Row_id 来
充当默认主键,而 Myisam 可以没有主键
3、InnoDB 的四大特性?
插入缓冲 (insert buffer)
二次写 (double write)
自适应哈希索引 (ahi)
预读 (read ahead)
4、InnoDB 为何推荐使用自增主键?
自增 ID 可以保证每次插入时 B+ 树索引是从右
边扩展的,因此相比自定义 ID (如 UUID) 可以
避免 B+ 树的频繁合并和分裂。如果使用字符
串主键和随机主键,会使得数据随机插入,效
率比较差
5、如何选择存储引擎?
默认使用 InnoDB,MyISAM 适用以插入为主
的程序,比如博客系统、新闻门户
五、存储结构
1、什么是 InnoDB 的页、区、段?
页(Page)
首先,InnoDB 将物理磁盘划分为页 (page),
每页的大小默认为 16 KB,页是最小的存储
单位。页根据上层应用的需要,如索引、日
志等,分为很多的格式。我们主要说数据页,
也就是存储实际数据的页。
区(Extent)
如果只有页这一个层次的话,页的个数是非
常多的,存储空间的分配和回收都会很麻烦,
因为要维护这么多的页的状态是非常麻烦的。
所以,InnoDB 又引入了区 (Extent) 的概念。
一个区默认是 64 个连续的页组成的,也就
是 1MB。通过 Extent 对存储空间的分配和
回收就比较容易了。
段(Segment)
为什么要引入段呢,这要从索引说起。我们
都知道索引的目的是为了加快查找速度,是
一种典型的用空间换时间的方法
B+ 树的叶子节点存放的是我们的具体数据,
非叶子结点是索引页。所以 B+ 树将数据分
为了两部分,叶子节点部分和非叶子节点部
分,也就我们要介绍的段 (Segment),也就
是说 InnoBD 中每一个索引都会创建两个
Segment 来存放对应的两部分数据
Segment 是一种逻辑上的组织,其层次结
构从上到下一次为 Segment、Extent、
Page
2、页由哪些数据组成?
首先看数据页的基本格式,如下图:
File Header
用于描述数据页的外部信息,比如属于哪
一个表空间、前后页的页号等
Page Header
用来描述数据页中的具体信息,比如存在
多少条纪录,第一条纪录的位置等
infimum 和 supremum 纪录
infimum 和 supremum 是系统生成的纪录,
分别为最小和最大纪录值,infimum 的下一
条是用户纪录中键值最小的纪录,supremum
的上一条是用户纪录中键值最大的纪录,通
过 next_record 字段来相连。
User Records
用户纪录,也就是数据库表中对应的数据,
这里我们说常用的 Compact 格式。InnoDB
除了我们插入的数据外,还有一些隐藏列,
transaction_id (事务ID)、roll_pointer (回滚
指针) 是一定添加的
row_id 则不一定,根据以下策略生成:优
先使用用户建表时指定的主键,若用户没
有指定主键,则使用 unique 键。若 unique
键都没有,则系统自动生成 row_id,为隐
藏列
Free Space
页中目前空闲的存储,可以插入纪录
Page Dictionary
类似于字典的目录结构,根据主键大小,每
隔 4-8 个纪录设置一个槽,用来纪录其位置,
当根据主键查找数据时,首先一步到位找到
数据所在的槽,然后在槽中线性搜素。这种
方法比从前到后遍历页的链表的效率更快
Page Tailer
File Header 存储刷盘前内存的校验和,Page
Tailer 储存刷盘后的校验和。当刷盘的时候,
出现异常,Page Tailer 和 File Header 中的校
验和不一致,则说明出现刷盘错误
3、页中插入记录的过程?
① 如果 Free Space 的空间足够的话,直接分
配空间来添加纪录,并将插入前最后一条纪
录的 next_record 指向当前插入的纪录,将
当前插入纪录的 next_record 指向 supremum
纪录
② 如果 Free Space 的空间不够的话,则首先
将之前删除造成的碎片重新整理之后,按照
上述步骤插入纪录
③ 如果当前页空间整理碎片之后仍然不足的话,
则重新申请一个页,将页初始化之后,按照上
述步骤插入纪录
4、什么是 Buffer Pool?
Buffer Pool 是 InnoDB 存储引擎层的缓冲池,
不属于 MySQL 的 Server 层,注意跟 8.0 删
掉的“查询缓存”功能区分
内存中以页 (page) 为单位缓存磁盘数据,减
少磁盘 IO,提升访问速度。缓冲池大小默认
128M,独立的 MySQL 服务器推荐设置缓冲
池大小为总内存的 80%。主要存储数据页、
索引页更新缓冲 (change buffer) 等
预读机制
Buffer Pool 有一项特技叫预读,存储引擎的
接口在被 Server 层调用时,会在响应的同时
进行预判,将下次可能用到的数据和索引加
载到
Buffer Pool 预读策略有两种,为线性预读
(linear read-ahead)和随机预读 (random
read-ahead),其中 InnoDB 默认使用线性
预读,随机预读已经基本废弃
线性预读认为如果前面的请求顺序访问当前
区 (extent) 的页,那么接下来的若干请求也
会顺序访问下一个区的页,并将下一个区加
载到 Buffer Pool。在 5.4 版本以后默认开启,
默认值为 56,最大不能超过 64,表示顺序
访问 N 个页后触发预读 (一个页 16K,一个
区 1M,一个区最多 64 个页,所以最大值
64)
换页算法
与传统的 LRU 算法不同,因为面临两个问题:
① 预读失效:由于提前把页放入了缓冲池,
但最终 MySQL 并没有从页中读取数据。
要优化预读失效,则让预读失败的页停
留在缓冲池里的时间尽可能短,预读成
功的页停留时间尽可能长。具体将 LRU
链分代实现,即新生代和老年代 (old
subList),预读的页加入缓冲池时只加
入到老年代头部,只有真正被预读成功,
则再加入新生代
② 缓冲池污染:当批量扫描大量数据时,
可能导致把缓冲池的所有页都替换出去,
导致大量热数据被换出,MySQL 性能急
剧下降。
InnoDB 缓冲池加入了一个老生代停留时间窗
口的机制,只有满足预读成功并且在老生代停
留时间大于该窗口才会被放入新生代头部
5、什么是 Change Buffer?
如果每次写操作,数据库都直接更新磁盘
中的数据,会很占磁盘 IO。为了减少磁盘
IO,InnoDB 在 Buffer Pool 中开辟了一块
内存,用来存储变更记录,为了防止异常
宕机丢失缓存,当事务提交时会将变更记
录持久化到磁盘 (redo log),等待时机更新
磁盘的数据文件 (刷脏),用来缓存写操作
的内存,就是 Change Buffer
Change Buffer 默认占 Buffer Pool 的 25%,
最大设置占用 50%
六、 InnoDB
1、InnoDB 架构设计?
以下主要从内存和线程的角度分析 InnoDB 的架构
内存中的数据区域划分:
2、InnoDB 有哪些线程?
线程的作用:
① 负责刷新内存池中的数据,保证缓冲池
的内存缓冲的是最近的数据
② 已修改的数据文件刷新到磁盘文件
③ 保证数据库发生异常的情况下 InnoDB
能恢复到正常状态
线程分类:
① Master Thread
负责将缓冲池中的数据异步刷新到磁盘,
保证数据的一致性,包括脏页的刷新,
合并插入缓冲(INSERT BUFFER),
UNDO 页的回收等
② IO Thread
负责 AIO 请求的回调处理
③ Purge Thread
事务提交后,undo log 可能不再需要,
由 Purge Thread 负责回收并重新分配
的这些已经使用的 undo 页
④ Page Cleaner Thread
将 Master Threader 中刷新脏页的工作
移至该线程,如上面说的 FLUSH LRU
LIST Checkpoint 以及 Async/Sync Flush
Checkpoint
3、什么是 doublewrite?
Double write 是 InnoDB 在 tablespace
(ibdata1) 上的128个页(2个区)是2MB
4、什么是自适应哈希?
InnoDB 会监控对表上各索引页的查询执
行情况,如发现建立哈希索引可以提升速
度,则建立哈希索引,这是过程不需要用
户干预 (默认开启)
七、事务
1、什么是数据库的事务?
数据库的事务是一个不可分割的数据库操
作序列,也是数据库并发控制的基本单位,
其执行的结果必须使数据库从一种一致性
状态变到另一种一致性状态。事务是逻辑
上的一组操作,要么都执行,要么都不执
行
事务的典型应用场景,如转账
2、什么是事务的四大特性(ACID)?
原子性: 事务是最小的执行单位,不允许
分割。事务的原子性确保动作要么全部完
成,要么完全不起作用
一致性: 事务执行前后,数据保持一致,多个事务对同一个数据读取的结果是相同
的
隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之
间数据库是独立的
持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发
生故障也不应该对其有任何影响
3、事务的并发问题?
脏读
幻读
不可重复读
4、什么是脏读、幻读和不可重复度?
脏读:一个事务读取到另一个事务尚未提交
的数据。 事务 A 读取事务 B 更新的数据,
然后 B 回滚操作,那么 A 读取到的数据是
脏数据
不可重复读:一个事务中两次读取的数据的
内容不一致。事务 A 多次读取同一数据,事
务 B 在事务 A 多次读取的过程中,对数据作
了更新并提交,导致事务 A 多次读取同一数
据时,结果不一致
幻读:一个事务中两次读取的数据量不一致。
系统管理员 A 将数据库中所有学生的成绩从
具体分数改为 ABCDE 等级,但是系统管理
员 B 就在这个时候插入了一条具体分数的记
录,当系统管理员 A 改结束后发现还有一条
记录没有改过来,就好像发生了幻觉一样,
这就叫幻读
不可重复读的和幻读很容易混淆,不可重复
读侧重于修改,幻读侧重于新增或删除
解决不可重复读的问题只需锁住满足条件的
行,解决幻读需要锁表
5、事务的隔离级别有哪些?
串行化的隔离级别最高,读未提交的级别最
低,级别越高,则执行效率就越低,所以在
选择隔离级别时应该结合实际情况。
MySQL 支持以上四种隔离级别,默认为
Repeatable read (可重复读);
而 Oracle 只支持 Serializeble (串行化) 级别
和 Read committed (读已提交) 两种,其中
默认为读已提交
6、ACID 特性是如何实现的?
分四个维度去理解,如原子性是 undo 日志,
持久性是 redo 日志
八、锁
1、数据库锁的作用以及有哪些锁?
当数据库有并发事务的时候,可能会产生数
据的不一致,这时候需要一些机制来保证访
问的次序,锁机制就是这样的一个机制,即
锁的作用是解决并发问题
从锁的粒度划分,可以将锁分为表锁、行锁以及
页锁
行级锁:是锁定粒度最细的一种锁,表示只针
对当前操作的行进行加锁。行级锁能大大减少
数据库操作的冲突。其加锁粒度最小,但加锁
的开销也最大
行级锁开销大,加锁慢,且会出现死锁。但锁定粒度最小,发生锁冲突的概率最低,并发度
也最高
表级锁:是粒度最大的一种锁,表示对当前操
作的整张表加锁,它实现简单,资源消耗较少,
被大部分 MySQL 引擎支持
页级锁:是粒度介于行级锁和表级锁中间的一
种锁。表级锁速度快,但冲突多,行级冲突少,
但速度慢。所以取了折中的页级,一次锁定相
邻的一组记录
开销和加锁时间界于表锁和行锁之间,会出现
死锁;
锁定粒度界于表锁和行锁之间,并发度一般
从使用性质划分,可以分为共享锁、排它锁以及
更新锁。
共享锁 (Share Lock):S 锁,又称读锁,
用于所有的只读数据操作
S 锁并非独占,允许多个并发事务对同一资源加锁,但加 S 锁的同时不允许加 X 锁,
即资源不能被修改。S 锁通常读取结束后立
即释放,无需等待事务结束
排他锁 (Exclusive Lock):X 锁,又称写锁,
表示对数据进行写操作
X 锁仅允许一个事务对同一资源加锁,且直到事务结束才释放,其他任何事务必须等到
X 锁被释放才能对该页进行访问
使用 select * from table_name for update;
语句产生 X 锁
更新锁:U 锁,用来预定要对资源施加 X 锁,
允许其他事务读,但不允许再施加 U 锁或 X
锁
当被读取的页将要被更新时,则升级为 X 锁,U 锁一直到事务结束时才能被释放。故 U 锁
用来避免使用共享锁造成的死锁现象
从主观上划分,又可以分为乐观锁和悲观锁
乐观锁 (Optimistic Lock):顾名思义,从主观
上认定资源是不会被修改的,所以不加锁读取
数据,仅当更新时用版本号机制等确认资源是
否被修改
乐观锁适用于多读的应用类型,可以系统提高吞吐量
悲观锁 (Pessimistic Lock):正如其名,具有强
烈的独占和排它特性,每次读取数据时都会认
为会被其它事务修改,所以每次操作都需要加
上锁
2、隔离级别和锁的关系?
① 在 Read Uncommitted 级别下,读取数据
不需要加共享锁,这样就不会跟被修改的数
据上的排他锁冲突;
② 在 Read Committed 级别下,读操作需要
加共享锁,但是在语句执行完以后释放共享
锁;
③ 在 Repeatable Read 级别下,读操作需要
加共享锁,但是在事务提交之前并不释放共
享锁,也就是必须等待事务执行完毕以后才
释放共享锁;
④ 在 SERIALIZABLE 级别下,限制性最强,
因为该级别锁定整个范围的键,并一直持有
锁,直到事务完成
3、InnoDB 中的锁算法?
Record lock:单个行记录上的锁
Gap lock:间隙锁,锁定一个范围,不包括记录本身
Next-key lock:record + gap 锁定一个范围,包含记录本身
4、什么是快照读和当前读?
快照读就是读取的是快照数据,不加锁的简单
Select 都属于快照读
SELECT * FROM player WHERE ...
当前读就是读的是最新数据,而不是历史的数
据。加锁的 SELECT,或者对数据进行增删改
都会进行当前读。
SELECT * FROM player LOCK IN SHARE MODE;
SELECT FROM player FOR UPDATE;
INSERT INTO player values ...
DELETE FROM player WHERE ...
UPDATE player SET ...
5、什么是 MVCC 以及实现?
MVCC 的英文全称是 Multiversion Concurrency
Control,中文意思是多版本并发控制,可以做
到读写互相不阻塞,主要用于解决不可重复读
和幻读问题时提高并发效率
其原理是通过数据行的多个版本管理来实现数
据库的并发控制,简单来说就是保存数据的历
史版本。可以通过比较版本号决定数据是否显
示出来。读取数据的时候不需要加锁可以保证
事务的隔离效果