数据库(MySQL)面经

1 请介绍一下三个范式?

  1. 第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。
  2. 第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。
  3. 第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖,指的是如果存在"A → B → C"的决定关系,则C传递函数依赖于A。因此,满足第三范式的数据库表应该不存在如下依赖关系: 关键字段 →非关键字段 x → 非关键字段y

2 什么是 B-Tree?

B_TREE 是一种平衡多路查找树,是一种动态查找效率很高的树形结构。B_TREE 中所有结点的孩子结点的最大值称为 B_TREE 的阶,B_TREE 的阶通常用 m 表示,简称为 m 叉树。一般来说,应该是 m>=3。一颗 m 阶的 B_TREE 或是一颗空树,或者是满足下列条件的 m 叉树:

  1. 树中每个结点最多有 m 个孩子结点
  2. 若根结点不是叶子节点,则根结点至少有2个孩子结点
  3. 除根结点外,其它结点至少有( m/2 的上界)个孩子结点
  4. 结点的结构如下图所示,其中,n 为结点中关键字个数,(m/2 的上界)-1 <= n <= m-1;di(1<= i <= n) 为该结点的 n 个关键字值的第 i 个,且di < d(i+1);ci(0<= i <=n)为该结点孩子结点的指针,且 ci 所指向的节点的关键字均大于或等于 di 且小于 d(i+1)
    在这里插入图片描述
  5. 所有的叶结点都在同一层上,并且不带信息(可以看作是外部结点或查找失败的结点,实际上这些结点不存在,指向这些结点的指针为空)

在这里插入图片描述
B_TREE 的查找类似二叉排序树的查找,所不同的是 B-树每个结点上是多关键码的有序表,在到达某个结点时,先在有序表中查找,若找到,则查找成功;否则,到按照对应的指针信息指向的子树中去查找,当到达叶子结点时,则说明树中没有对应的关键码。由于 B_TREE 的高检索效率,B-树主要应用在文件系统和数据库中,对于存储在硬盘上的大型数据库文件,可以极大程度减少访问硬盘次数,大幅度提高数据检索效率。

无论二叉搜索树还是 AVL 树,当数据量比较大时,都会由于树的深度过大而造成 I/O 读写过于频繁,进而导致查询效率低下,因此对于索引而言,多叉树结构成为不二选择。特别地,B-Tree 的各种操作能使 B 树保持较低的高度,从而保证高效的查找效率。

3 什么是 B+Tree?

B+Tree 是 InnoDB 存储引擎的索引实现。B+Tree 是应文件系统所需而产生的一种 B_TREE 树的变形树。一棵 m 阶的 B+ 树和 m 阶的 B_TREE 的差异在于以下三点:

  1. n 棵子树的结点中含有n个关键码;
  2. 所有的叶子结点中包含了全部关键码的信息,及指向含有这些关键码记录的指针,且叶子结点本身依关键码的大小自小而大的顺序链接;
  3. 非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键码。

下图为一棵3阶的 B+ 树。通常在 B+ 树上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点。因此可以对 B+ 树进行两种查找运算:一种是从最小关键字起顺序查找,另一种是从根节点开始,进行随机查找。 在 B+ 树上进行随机查找、插入和删除的过程基本上与 B-树类似。只是在查找时,若非终端结点上的关键码等于给定值,并不终止,而是继续向下直到叶子结点。因此,对于 B+ 树,不管查找成功与否,每次查找都是走了一条从根到叶子结点的路径。
在这里插入图片描述

4 为什么说 B+ 树比 B 树更适合实际应用中操作系统的文件索引和数据库索引?

  1. B+ 树的磁盘读写代价更低:B+ 树的内部结点并没有指向关键字具体信息的指针,因此其内部结点相对 B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多,相对来说 IO 读写次数也就降低了;
  2. B+ 树的查询效率更加稳定:由于内部结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引,所以,任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当;
  3. 数据库索引采用 B+ 树而不是 B 树的主要原因:B+ 树只要遍历叶子节点就可以实现整棵树的遍历,而且在数据库中基于范围的查询是非常频繁的,而 B 树只能中序遍历所有节点,效率太低。

5 什么情况下设置了索引但无法使用?

  1. 以 “%(表示任意0个或多个字符)” 开头的 LIKE 语句,模糊匹配
  2. OR 语句前后没有同时使用索引
  3. 数据类型出现隐式转化(如 varchar 不加单引号的话可能会自动转换为 int 型)
  4. 对于多列索引,必须满足最左匹配原则,例如存在多列索引 col1、col2 和 col3,则索引生效的情形包括 col1 或 col1,col2 或 col1,col2,col3。

6 索引的优点与缺点?

优点:

  1. 大大加快数据的检索速度,这也是创建索引的最主要的原因
  2. 加速表和表之间的连接
  3. 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间
  4. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性

缺点:

  1. 时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度
  2. 空间方面:索引需要占物理空间

对数据进行频繁查询需要建立索引,如果要频繁更改数据不建议使用索引。

7 有哪几种索引?

  1. hash 索引:适用于等值查询,不能排序,不能进行范围查询
  2. 有序数组:适用于等值查询和范围查询。但由于往中间插入一条数据,必须挪动后面的所有记录,成本较高,所以只适用于静态存储引擎,即数据表一旦建立后不再会修改。
  3. B+ 索引:适用于数据有序,范围查询

8 什么样的字段适合创建索引?什么情况下不宜建立索引?

适合创建索引:

  1. 经常作查询选择的字段
  2. 经常作表连接的字段
  3. 经常出现在 order by, group by, distinct 后面的字段

不适合创建索引:

  1. 对于查询中很少涉及的列或者重复值比较多的列,不宜建立索引
  2. 对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等

9 创建索引时需要注意什么?

  1. 非空字段:应该指定列为 NOT NULL,除非你想存储 NULL。在 MySQL 中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值
  2. 取值离散大的字段:(变量各个取值之间的差异程度)的列放到联合索引的前面,可以通过 count() 函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高
  3. 索引字段越小越好:数据库的数据存储以页为单位,一页存储的数据越多,一次 IO 操作获取的数据越大,效率越高

10 索引的分类?

  1. 普通索引和唯一性索引:索引列的值的唯一性
  2. 单个索引和复合索引:索引列所包含的列数
  3. 聚簇索引与非聚簇索引:在 InnoDB 中,聚簇索引又称主键索引,它的叶子节点存的是整行数据。主键查询主需要扫描主键索引。二级索引又称非主键索引,它的叶子节点内容是主键的值。通过二级索引需要扫描二级索引树,找到主键后再扫描主键索引。该过程称为回表。

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

主键索引指的就是主键,主键是索引的一种,是唯一索引的特殊类型。创建主键的时候,数据库默认会为主键创建一个唯一索引;唯一索引表示索引列的值必须唯一,但允许有空值。主键是唯一索引,这样说没错;但反过来说,唯一索引也是主键就错误了,因为唯一索引允许空值,主键不允许有空值,所以不能说唯一索引也是主键。

12 什么是事务?

事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。

13 事务的特征(ACID)?

  1. 原子性(Atomicity):事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
  2. 一致性(Consistency):事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。
  3. 隔离性(Isolation):关于事务的隔离性数据库提供了多种隔离级别:一个事务的执行不能干扰其它事务。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
  4. 持久性(Durability):事务完成之后,它对于数据库中的数据改变是永久性的。该修改即使出现系统故障也将一直保持。

14 事务的隔离级别?

  1. 读未提交:一个事务还未提交,其他事务就可以看到它做的更改
  2. 读已提交:大多数数据库系统的默认隔离级别,一个事务在提交之后,其他事务才能看到它的更改
  3. 可重复读:mysql 默认隔离级别,一个事务是启动和提交之间读到数据是一致的,它在未提交时,其他事务无法看到它做的更改
  4. 串行化:对同一行记录,写会加写锁,读会加读锁,当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完才能继续执行

15 事务并发带来的问题?

  1. 脏读:一个事务读取了另一个事务未提交的数据
  2. 不可重复读:不可重复读的重点是修改,同样条件下两次读取结果不同,也就是说,被读取的数据可以被其它事务修改
  3. 幻读:幻读的重点在于新增或者删除,同样条件下两次读出来的记录数不一样
    在这里插入图片描述

16 MySQL 的事务支持?

MySQL 的事务支持不是绑定在 MySQL 服务器本身,而是与存储引擎相关:MyISAM 是不支持事务的,而 InnoDB 是支持事务的。

17 如何优化 MySQL?

可以考虑以下四个方面:

  1. SQL 语句及索引的优化
  2. 数据表结构的优化
  3. 系统配置的优化
  4. 硬件的优化

18 优化 MySQL – SQL 语句及索引的优化?

对于 SQL 语句,我们可以通过慢查询日志对有效率问题的 SQL 进行监控,可以通过 explain 查询和分析 SQL 的执行计划。使用 explain 查询可以得到表的读取顺序、数据读取操作的操作类型、哪些索引可以使用、哪些索引被实际使用、表之间的引用以及每张表有多少行被优化器查询等问题,可以据此分析查询语句或是表结构的性能瓶颈。

那么 SQL 语句如何优化呢?

  1. 优化 insert 语句:一次插入多值
  2. 应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描
  3. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
  4. 优化嵌套查询:子查询可以被更有效率的连接(Join)替代
  5. 很多时候用 exists 代替 in 是一个好的选择

对于索引的优化可以参考我上面提到的什么样的字段适合创建索引以及什么情况下不宜建立索引。

19 优化 MySQL – 数据库表结构的优化?

  1. 选择合适数据类型
  2. 表的范式的优化
  3. 表的垂直拆分
  4. 表的水平拆分

选择合适数据类型

  1. 使用较小的数据类型解决问题
  2. 使用简单的数据类型( MySQL 处理 int 要比 varchar 容易)
  3. 尽可能的使用 not null 定义字段
  4. 尽量避免使用 text 类型,非用不可时最好考虑分表

表的范式的优化

参考上文提到过的三大范式

表的垂直拆分

把含有多个列的表拆分成多个表,解决表宽度问题,具体包括以下几种拆分手段:

  1. 把不常用的字段单独放在同一个表中
  2. 把大字段独立放入一个表中
  3. 把经常使用的字段放在一起

这样做的好处是非常明显的,具体包括:拆分后业务清晰,拆分规则明确、系统之间整合或扩展容易、数据维护简单。

表的水平拆分

表的水平拆分用于解决数据表中数据过大的问题,水平拆分每一个表的结构都是完全一致的。一般地,将数据平分到 N 张表中的常用方法包括以下两种:

  1. 对 ID 进行 hash 运算,如果要拆分成5个表,mod(id,5) 取出0~4个值
  2. 针对不同的 hashID 将数据存入不同的表中

表的水平拆分会带来一些问题和挑战,包括跨分区表的数据查询、统计及后台报表的操作等问题,但也带来了一些切实的好处:

  1. 表分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询速度
  2. 表中的数据本来就有独立性,例如表中分别记录各个地区的数据或不同时期的数据,特别是有些数据常用,而另外一些数据不常用
  3. 需要把数据存放到多个数据库中,提高系统的总体可用性(分库,鸡蛋不能放在同一个篮子里)

20 什么是存储过程?有哪些优缺点?

存储过程是一些预编译的 SQL 语句。更加直白的理解:存储过程可以说是一个记录集,它是由一些 T-SQL 语句组成的代码块,这些 T-SQL 语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。存储过程是一个预编译的代码块,执行效率比较高,一个存储过程替代大量 T_SQL 语句 ,可以降低网络通信量,提高通信速率,可以一定程度上确保数据安全。

21 drop、delete 与 truncate 的区别?drop、delete 与 truncate 分别在什么场景之下使用?

SQL 中的 drop、delete、truncate 都表示删除,但是三者有一些差别的:

  1. Delete 用来删除表的全部或者一部分数据行,执行 delete 之后,用户需要提交 (commmit) 或者回滚 (rollback) 来执行删除或者撤销删除, delete 命令会触发这个表上所有的 delete 触发器
  2. Truncate 删除表中的所有数据,这个操作不能回滚,也不会触发这个表上的触发器,TRUNCATE 比 delete 更快,占用的空间更小
  3. Drop 命令从数据库中删除表,所有的数据行,索引和权限也会被删除,所有的 DML 触发器也不会被触发,这个命令也不能回滚

因此,在不再需要一张表的时候,用 drop;在想删除部分数据行时候,用 delete;在保留表而删除所有数据的时候用 truncate。

22 什么是视图?以及视图的使用场景有哪些?

  1. 视图是一种虚拟的表,具有和物理表相同的功能。可以对视图进行增,改,查,操作,试图通常是有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得我们获取数据更容易,相比多表查询
  2. 只暴露部分字段给访问者,所以就建一个虚表,就是视图
  3. 查询的数据来源于不同的表,而查询者希望以统一的方式查询,这样也可以建立一个视图,把多个表查询结果联合起来,查询者只需要直接从视图中获取数据,不必考虑数据来源于不同表所带来的差异

23 什么是触发器?

触发器是与表相关的数据库对象,在满足定义条件时触发,并执行触发器中定义的语句集合。触发器的这种特性可以协助应用在数据库端确保数据库的完整性。

24 数据库的乐观锁和悲观锁是什么?

数据库管理系统中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

  1. 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。其特点为特点是先获取锁,再进行业务操作。一般在数据库我们使用 select … for update 来实现悲观锁。当数据库执行 select … for update 时会获取被 select 中的数据行的行锁,因此其他并发执行的 select … for update 如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update 获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。(注意:在 MySQL 中, select… for update 语句执行中所有扫描过的行都会被锁上,所以如果在 MySQL 中用悲观锁务必要确定使用了索引,而不是全表扫描)
  2. 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。乐观锁的特点先进行业务操作,只在最后实际更新数据时进行检查数据是否被更新过,若未被更新过,则更新成功;否则,失败重试。乐观锁一般的做法是在需要锁的数据上增加一个版本号或者时间戳。然后操作如下:
1. SELECT data AS old_data, version AS old_version FROM;
2. 根据获取的数据进行业务操作,得到new_data和new_version
3. UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
    // 乐观锁获取成功,操作完成
} else {
    // 乐观锁获取失败,回滚并重试
}

一般情况下,读多写少更适合用乐观锁,读少写多更适合用悲观锁。乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能。

25 MyISAM 和 InnoDB 的区别?

MyISAM 和 InnoDB 都是 MySQL 的存储引擎,它们的区别如下:

  1. 存储空间:MyISAM 可被压缩,占据的存储空间较小;InnoDB 需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。
  2. 事务支持:MyISAM 强调的是性能,每次查询具有原子性,其执行数度比 InnoDB 类型更快,但是不提供事务支持;InnoDB 提供事务、外键等高级数据库功能,具有事务提交、回滚和崩溃修复能力。
  3. 表锁差异:MyISAM 只支持表级锁,用户在操作 MyISAM 表时,select、update、delete 和 insert 语句都会给表自动加锁;InnoDB 支持事务和行级锁。行锁大幅度提高了多用户并发操作的性能,但是 InnoDB 的行锁,只是在 WHERE 的主键是有效的,非主键的 WHERE 都会锁全表的。
  4. 外键:MyISAM 不支持外键,而 InnoDB 支持外键。
  5. 表的具体行数:MyISAM 保存表的总行数,而 InnoDB 没有保存表的总行数。
    在这里插入图片描述

参考:面试/笔试第三弹 —— 数据库面试问题集锦

发布了116 篇原创文章 · 获赞 210 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Geffin/article/details/104043595