MySQL面试系列-01

2022年7月17日
大约 18 分钟

MySQL面试系列-01

1. 数据库中什么是事务?

事务(transaction)是指数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元)。

通俗的说就是事务可以作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功,则认为事务成功,即使只有一个操作失败,事务也不成功。如果所有操作完成,事务则提交,其修改将作用于所有其他数据库进程。如果一个操作失败,则事务将回滚,该事务所有操作的影响都将取消。

2. MySQL 事务都有哪些特性?

事务的四大特性:

1 、原子性

事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做

2 、一致性

事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。

3 、隔离性

一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

4 、持续性

也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。

3. MySQL 的索引有哪些设计原则?

选择唯一性索引

唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录

作为查询条件的字段建立索引

某个字段用来做查询条件,那么该字段的查询速度会影响整个表的查询速度。因此,为该字段建立索引,可以提高整个表的查询速度

限制索引的数量

索引的数量并不是越多越好,每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。

修改表时,索引过多会使得更新表速度变慢

尽量使用字段数据量少的索引

若索引的字段数据量过长,会导致查询的速度变慢

如:对一个char(200)类型的字段进行全文检索需要的时间肯定比对char(10)类型的字段需要的时间更多

排序、分组和联合字段建立索引

使用order by、group by、distinct和union等操作的字段进行排序操作会浪费很多时间。若为其建立索引,可以有效的避免排序操作

尽量使用前缀索引

索引字段的值很长,最好使用值的前缀来索引

如:text和blog类型的字段,进行全文检索会浪费时间。若只检索字段的部分若干个字符,可以提高检索速度

删除不使用或者很少使用的索引

表中数据被批量更新或数据的使用方式被改变后,原有的一些索引可能不再需要。应当定期清理这些索引

小表不创建索引(超过200w数据的表,创建索引)

包含很多列且不需要搜索非空值时可以考虑不建索引

被用来过滤记录的字段创建索引

primary key 字段,系统自动创建主键的索引 unique key 字段,系统自动创建对应的索引 foreign key 约束所定义的作为外键的字段 在查询中用来连接表的字段 用作为排序(order by的字段)的字段

创建索引必须考虑数据的操作方式,原则是内容变动少,经常被用于查询的字段创建索引,对于经常性变动的表而言,则需要谨慎创建必要的索引

4. 【美团】MySQL 日志文件有哪些,都有什么作用?

MySQL中有三种log,分别是:binlog、redo log、undo log。

binlog

binlog是用于记录数据库表结构和表数据变更的二进制日志,比如insert、update、delete、create、truncate等等操作,不会记录select、show操作,因为没有对数据本身发生变更。

  • 主从复制

  • 三种模式: STATEMENT、ROW、MIXED

redo log

事务持久性,用于崩溃恢复,innodb是以页为单位进行磁盘IO的,每次事务完毕要保证持久性,就要迅速刷盘,性能差,因此采用redolog日志。

undo log

undo log的作用主要用于回滚,mysql数据库的事务的原子性就是通过undo log实现的。我们都知道原子性是指对数据库的一系列操作,要么全部成功,要么全部失败。

undo log主要存储的是数据的逻辑变化日志。

  • 并发控制;1)MVCC;2)ReadView

  • 事务回滚。

5. MySQL支持哪些分区类型?

RANGE分区: 基于属于一个给定连续区间的列值,把多行分配给分区。这种模式允许将数据划分不同范围。例如可以将一个表通过年份划分成若干个分区。

LIST分区: 类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择。这种模式允许系统通过预定义的列表的值来对数据进行分割。按照List中的值分区,与RANGE的区别是,range分区的区间范围值是连续的。

HASH分区: 基于用户定义的表达式的返回值来进行选择的分区,该表达式使用将要插入到表中的这些行的列值进行计算。这中模式允许通过对表的一个或多个列的HashKey进行计算,最后通过这个Hash码不同数值对应的数据区域进行分区。例如可以建立一个对表主键进行分区的表。

KEY分区: Hash模式的一种延伸,类似于按HASH分区,区别在于KEY分区只支持计算一列或多列且MySQL服务器提供其自身的哈希函数。必须有一列或多列包含整数值。

6. 如何判断 MySQL 是否支持分区?

如果mysql5.6以下版本,使用SHOW VARIABLES语句来确定MySQL数据库是否支持分区:

show variables like '%partition%';

如果查询结果显示Empty,表示不支持分区,反之have_partintioning的值为YES,表示支持分区。但是需注意的此方式只针对mysql5.6以下版本。

如果mysql5.6及以上版本,需要使用show plugins;查询命令。查询方法显示所有插件,有红色部分(如下)的话,表示支持分区。

partition                  | ACTIVE   | STORAGE ENGINE     | NULL    | GPL  

7. MySQL 中有哪几种隔离级别?

SQL标准定义了四种隔离级别,包括一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。

Read uncommitted (读未提交)

Read Committed也被称之为脏读(Dirty Read)。所有事务都可以看到其他未提交事务的执行结果。这个隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。

Read Committed(读已提交)

大多数数据库系统的默认隔离级别,但不是MySQL默认的。

Read Committed满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read(可重复读)

Repeatable Read是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。

不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(串行化)

Serializable是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言来说它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

8. MySQL 中行级锁都有哪些优缺点?

行级锁的优点

1)在许多线程请求访问不同的行时减少冲突锁。

2)事务回滚时减少改变数据。

3)可以长时间对单一的行数据加锁。

行级锁的缺点

1)比页级或表级锁定占用更多的内存。

2)当大量表中使用行级锁时,比页级锁或表级锁占用更多的内存。

3)如果需要频繁对大部分数据使用GROUP BY分组操作或者需要频繁扫描整个表时,明显比其它锁慢很多。

4)使用高级别锁时更方便的支持各种不同的类型应用程序,因为这种锁开销比行级锁要小很多。

9. 数据库引擎都有哪些?

InnoDB存储引擎是Mysql的默认存储引擎。InnoDB存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全。 但是对比MyISAM的存储引擎,InnoDB写的处理效率差一些,并且会占用更多的磁盘空间以保留数据和索引。

MyISAM不支持事务、也不支持外键,其优势是访问的速度快,对事务的完整性没有要求或者以SELECT、INSERT 为主的应用基本上都可以使用这个引擎来创建表。

Memory存储引擎将表的数据存放在内存中。每个MEMORY表实际对应一个磁盘文件,格式是.frm ,该文件中只 存储表的结构,而其数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率。MEMORY 类型的表访问非常地快,因为他的数据是存放在内存中的,并且默认使用HASH索引 ,但是服务一旦关闭,表中的 数据就会丢失。

MERGE存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,MERGE表本身并没有存储数据,对 MERGE类型的表可以进行查询、更新、删除操作,这些操作实际上是对内部的MyISAM表进行的。

10. MySQL 索引优化原则都有哪些?

对查询频次较高,且数据量比较大的表建立索引。

索引字段的选择,最佳候选列应当从where子句的条件中提取。

使用唯一索引,区分度越高,使用索引的效率越高。

使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率。

利用最左前缀,N个列组合而成的组合索引,那么相当于是创建了N个索引。

11. 什么是数据库三范式?

第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。

第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。

第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖,指的是如果存在”A → B → C”的决定关系,则C传递函数依赖于A。

12. MySQL 中内连接、左连接、右连接有什么区别?

1)内连接,显示两个表中有关联的所有数据;

2)左链接,以左表为参照,显示左表所有数据,右表中没有则显示null;

3)右链接,以右表为参照,显示右表所有数据,左表中没有则显示null。

13. MySQL 中 B+ 树索引和哈希索引有什么区别?

B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接,是有序的。

哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可,是无序的。

14. 哈希索引不适用哪些场景?

1、不支持范围查询;

2、不支持索引完成排序;

3、不支持联合索引的最左前缀匹配规则。

通常,B+树索引结构适用于绝大多数场景,像下面这种场景用哈希索引才更有优势:

在HEAP表中,如果存储的数据重复度很低(也就是说基数很大),对该列数据以等值查询为主,没有范围查询、没有排序的时候,特别适合采用哈希索引,例如这种SQL:

仅等值查询

select id, name from table where name='李明';

而常用的 InnoDB 引擎中默认使用的是B+树索引,它会实时监控表上索引的使用情况。

如果认为建立哈希索引可以提高查询效率,则自动在内存中的“自适应哈希索引缓冲区”建立哈希索引(在InnoDB中默认开启自适应哈希索引)。

通过观察搜索模式,MySQL会利用index key的前缀建立哈希索引,如果一个表几乎大部分都在缓冲池中,那么建立一个哈希索引能够加快等值查询。

注意:在某些工作负载下,通过哈希索引查找带来的性能提升远大于额外的监控索引搜索情况和保持这个哈希表结构所带来的开销。

但某些时候,在负载高的情况下,自适应哈希索引中添加的read/write锁也会带来竞争,比如高并发的join操作。like操作和%的通配符操作也不适用于自适应哈希索引,可能要关闭自适应哈希索引。

15. 【字节跳动】B 树和 B+ 树有什么区别?

二叉树是指任何节点的左子节点的键值都小于当前节点的键值,右子节点的键值都大于当前节点的键值。

平衡二叉树/AVL树当二叉树非常极端,变成一个链表后,它就没有了二叉树的相关优秀性质了。所以在insert节点的时候,需要不断的旋转,来使二叉树平衡,最终使得其查询效率最高。调整一共分为四种情况:LL、RR、LR、RL。

B-树因为数据库中大部分数据都存在于磁盘,但是IO一次磁盘的代价相对来说比较大,我们需要尽可能的减少AVL树的深度,即增加每个节点的数据量。这便是B-树的由来。每一个节点称为页,也就是一个磁盘块。 B树相对于平衡二叉树,每个节点存储了更多的键值(key)和数据(data),并且每个节点拥有更多的子节点。

B+树是B-树的变形,相对于B-树来说,B+树最主要的不同之处就是其非叶子节点上是不存储数据的,数据全在叶子节点存储。这就意味着B+树比B-树更胖。因为B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。那么B+树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。而B树因为数据分散在各个节点,要实现这一点是很不容易的。

1、B树,每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为nul,叶子结点不包含任何关键字信息。

2、B+树,所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接

所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。(而B树的非终节点也包含需要查找的有效信息)。

16. 为什么说 B+ 比 B 树更适合实际应用中文件数据库索引?

1、B+的磁盘读写代价更低。

B+的内部结点并没有指向关键字具体信息的指针,因此其内部结点相对B树更小。

如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。

2、B+-tree的查询效率更加稳定。

由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

17. MySQL 中什么是联合索引?

1、联合索引是两个或更多个列上的索引。

对于联合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。

例如索引是key index(a,b,c),可以支持a 、a,b 、a,b,c 3种组合进行查找,但不支持b,c进行查找,当最左侧字段是常量引用时,索引就十分有效。

2、利用索引中的附加列,可以缩小搜索的范围,但使用一个具有两列的索引不同于使用两个单独的索引。

复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。

如果知道姓,电话簿将非常有用;如果知道姓和名,电话簿则更为有用,但如果只知道名不知道姓,电话簿将没有用处。

18. 在什么情况下应少创建或不创建索引?

1、表记录太少;

2、经常插入、删除、修改的表;

3、数据重复且分布平均的表字段,假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。

4、经常和主字段一块查询但主字段索引值比较多的表字段,

19. 什么是表分区?

表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。

20. 表分区与分表有什么区别?

分表: 指的是通过一定规则,将一张表分解成多张不同的表。比如将用户订单记录根据时间成多个表。

分表与分区的区别在于:分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表。