数据库面试知识点
2021-02-26 13:33:34 # 总结

数据库面试知识点(未完待续)

通用基础

事务与隔离级别

事务特性

ACID:原子性(要么做了,要么没做),一致性(多个事务对同一数据读出结果相同),隔离性(事务之间不会相互影响),持久性(事务被提交后,修改是永久的)。

并发事务导致问题

脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交 到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没 有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是 不正确的。

丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据, 那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修 改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取 A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。

不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束 时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修 改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不 一样的情况,因此称为不可重复读。

幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接 着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了 一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

注意不可重复读和幻读区别: 不可重复读的重点是修改比如多次读取一条记录发现其中某些列的值被修改,幻读的重点在于新增或者 删除比如多次读取一条记录发现记录增多或减少了

SQL事务四大隔离级别

  1. READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导 致脏读、幻读或不可重复读。
  2. READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读 或不可重复读仍有可能发生。
  3. REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务 自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
  4. SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个 执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及 幻读。

关于锁的内容,可以参见这篇Blog:传送门

锁的分类

表级锁,行级锁,页级锁。

页级锁: MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。页级进行了折衷,一次锁定相邻的一组记录。开销和加锁时间界于表锁和行锁之间,会出现死锁。锁定粒度介于表锁和行锁之间,并发度一般。

MyISAM采用表级锁(table-level locking)。 InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁。

InnoDB实现行级锁的的三种方式:

  1. Record Lock: 对索引项加锁,锁定符合条件的行。其他事务不能修改和删除加锁项;
  2. Gap Lock: 对索引项之间的“间隙”加锁,锁定记录的范围(对第一条记录前的间隙或最后一条将记录后的间隙加锁),不包含索引项本身。其他事务不能在锁范围内插入数据,这样就防止了别的事务新增幻影行(但不能阻止减少)。
  3. Next-key Lock: 锁定索引项本身和索引范围。即Record Lock和Gap Lock的结合。可解决幻读问题。

备注:InnoDB的行级锁是基于索引实现的,如果查询语句为命中任何索引,那么InnoDB会使用表级锁. 此外,InnoDB的行级锁是针对索引加的锁,不针对数据记录,因此即使访问不同行的记录,如果使用了相同的索引键仍然会出现锁冲突,

MySQL

索引

其实关于索引的内容有很多,包括二级索引,辅助索引等,这篇文章洗的十分全面,有时间详细研读一下。关于索引的详解:索引详解

  1. 聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据
  2. 非聚簇索引:数据存储和索引分开放,索引结构的叶子节点指向了数据的对应行,myisam通过 key_buffer 把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在 key buffer 命中时,速度慢的原因(磁盘 IO)。

InnoDB的索引

InnoDB使用的是聚簇索引,将主键组织到一棵B+树中,而行数据就储存在叶子节点上,若使用”where id = 14”这样的条件查找主键,则按照B+树的检索算法即可查找到对应的叶节点,之后获得行数据。

若对Name列进行条件搜索,则需要两个步骤:第一步在辅助索引B+树中检索Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引B+树种再执行一次B+树检索操作,最终到达叶子节点即可获取整行数据。(重点在于通过其他键需要建立辅助索引)

聚簇索引默认是主键,如果表中没有定义主键,InnoDB 会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB 会隐式定义一个主键来作为聚簇索引。InnoDB 只聚集在同一个页面中的记录。包含相邻健值的页面可能相距甚远。

MyISM的索引

MyISM使用的是非聚簇索引,非聚簇索引的两棵B+树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引B+树的节点存储了主键,辅助键索引B+树存储了辅助键。表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

索引采用B+树的原因

B+树只有叶节点存放数据,其余节点用来索引,而B-树是每个索引节点都会有Data域。所以从Mysql(Inoodb)的角度来看,B+树是用来充当索引的,一般来说索引非常大,尤其是关系性数据库这种数据量大的索引能达到亿级别,所以为了减少内存的占用,索引也会被存储在磁盘上。

那么Mysql如何衡量查询效率呢?– 磁盘IO次数。 B-树/B+树 的特点就是每层节点数目非常多,层数很少,目的就是为了就少磁盘IO次数,但是B-树的每个节点都有data域(指针),这无疑增大了节点大小,说白了增加了磁盘IO次数(磁盘IO一次读出的数据量大小是固定的,单个数据变大,每次读出的就少,IO次数增多,一次IO多耗时),而B+树除了叶子节点其它节点并不存储数据,节点小,磁盘IO次数就少。这是优点之一。

另一个优点是: B+树所有的Data域在叶子节点,一般来说都会进行一个优化,就是将所有的叶子节点用指针串起来。这样遍历叶子节点就能获得全部数据,这样就能进行区间访问啦。在数据库中基于范围的查询是非常频繁的,而B树不支持这样的遍历操作。

AVL 树和红黑树基本都是存储在内存中才会使用的数据结构。在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘IO读写过于频繁,进而导致效率低下的情况。

补充面试题

  1. 怎么样确定使用到了索引?通过Explain语句查看是否使用到了索引。