参考MySQL八股文连环45问(背诵版) - 知乎 (zhihu.com)
基础
1.范式
第一范式:强调的是列的原子性
第二范式:要求实体的属性完全依赖于主关键字。所谓完全 依赖是指不能存在仅依赖主关键字一部分的属性。(就是主键不可精简了)
第三范式:任何非主属性不依赖于其它非主属性(非主键内容之间不存在相互依赖)
2. MySQL 支持哪些存储引擎?
MySQL 支持多种存储引擎,比如 InnoDB,MyISAM,Memory,Archive 等等.在大多数的情况下,直接选择使用 InnoDB 引擎都是最合适的,InnoDB 也是 MySQL 的默认存储引擎。
MyISAM 和 InnoDB 的区别有哪些:
- InnoDB 支持事务,MyISAM 不支持
- InnoDB 支持外键,而 MyISAM 不支持
- InnoDB 是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高;MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针,主键索引和辅助索引是独立的。
- Innodb 不支持全文索引,而 MyISAM 支持全文索引,查询效率上 MyISAM 要高;
- InnoDB 不保存表的具体行数,MyISAM 用一个变量保存了整个表的行数。
- MyISAM 采用表级锁(table-level locking);InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。
3. 超键、候选键、主键、外键分别是什么?
- 超键:在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。(就是可以包含冗余属性的候选键)
- 候选键:即没有冗余元素的超键。
- 主键:数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)(从所有候选键中选一个用作标识符的候选键)。
- 外键:在一个表中存在的另一个表的主键称此表的外键。(一个表的非主属性关联着另一个表的主键)
4. SQL 约束有哪几种?
非空 + 唯一 + 主外键 + 检查
- NOT NULL(非空):
- UNIQUE(控制属性值唯一): 控件字段内容不能重复,一个表允许有多个 Unique 约束。
- PRIMARY KEY:
- FOREIGN KEY:
- CHECK(检查某些属性的范围):
5. MySQL 中的 varchar 和 char 有什么区别?
一个定长一个变长。如果确定长度使用char,否则尽量varchar
char 是一个定长字段,假如申请了char(10)
的空间,那么无论实际存储多少内容.该字段都占用 10 个字符,而 varchar 是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1,最后一个字符存储使用了多长的空间.
在检索效率上来讲,char > varchar,因此在使用中,如果确定某个字段的值的长度,可以使用 char,否则应该尽量使用 varchar.例如存储用户 MD5 加密后的密码,则应该使用 char。
6.MySQL中 in 和 exists 区别
MySQL中In与Exists的区别_in和exists的区别_lzcWHUT的博客-CSDN博客
in是先做某一个字段的子查询,结果集为B,然后把主表A要查的字段检查是否在子查询的结果集B里。相当于先做子查询在做主查询。
exist是对主表A的每一个记录拿到exist的子查询B里去对比,如果查到了就把这个记录保留下来,最后得到的是所有在B里有存在的A的记录集合。相当于二层循环。
MySQL中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环。
如果查询的两个表大小相当,那么用in和exists差别不大。
如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in。
not in 和not exists:如果查询语句使用了not in,那么内外表都进行全表扫描,没有用到索引;而not extsts的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快。
7.drop、delete与truncate的区别
delete删除指定行
truncate清空一张表,但结构还在
drop直接丢弃表或者数据库
8. 什么是存储过程?有哪些优缺点?
存储过程是一些预编译的 SQL 语句。包含对单表或者多表的一些操作,由于是预编译,效率会高一些。
理解是类似于预先设定好的函数,封装一堆操作,还能起个名。
事务
1.是什么
具有原子性
是一个不可分割的数据库操作序列,数据库并发控制的基本单位。使数据库从一个状态变换到另一个稳定状态。
比如转账:A减少1000元,B增加1000。整体具有原子性。
2. 介绍一下事务具有的四个特征acid
原子性a:事务中包含的各操作要么都做,要么都不做
一致性c:事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
隔离性i:事务之间互不干扰
持久性d:事务提交对数据库数据的影响是永久的,即使数据库出现故障也要完成提交的事务。
3. 说一下MySQL 的四种隔离级别
- Read Uncommitted(读取未提交内容) ->存在三大问题
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
- Read Committed(读取提交内容)->解决脏读
这是大多数数据库系统的默认隔离级别(但不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓 的 不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的 commit,所以同一 select 可能返回不同结果。
- Repeatable Read(可重读)->解决不可重复读
这是 MySQL 的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。
- Serializable(可串行化)->解决幻读
通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
4.三大并发问题
(5 封私信 / 18 条消息) 什么是脏读、不可重复读、幻读? - 知乎 (zhihu.com)
Mysql的四个隔离级别是如何实现的_mysql四个隔离级别配置-CSDN博客
脏读:事务A读取到了事务B中未提交的数据,当事务B回滚后,事务A读取到的数据都是脏数据。
不可重复读:事务A多次读取同一数据,但每次读取的值不同。这是因为事务B在A的读取之间更新和提交新数据。
幻读:事务A在多次查询中,表数据多次新增或删除,导致几次查询都出现新增数据或者缺少记录。
不可重复读侧重的是数据的修改,幻读侧重的是数据的新增或删除。解决不可重复读,只有锁住行,而解决幻读,需要锁住整张表。
5. 事务的实现原理(redo重做和undo撤销)
事务是基于重做日志文件(redo log)和回滚日志(undo log)实现的。
每提交一个事务必须先将该事务的所有日志写入到重做日志文件进行持久化,数据库就可以通过重做日志来保证事务的原子性和持久性。
每当有修改事务时,还会产生 undo log,如果需要回滚,则根据 undo log 的反向语句进行逻辑操作,比如 insert 一条记录就 delete 一条记录。undo log 主要实现数据库的一致性
7. 什么是MySQL的 binlog?
MySQL的 binlog 是记录所有数据库表结构变更,比如增删改,查询不包含因为不变更表结构,需要看查询要去通用日志看。
8. 在事务中可以混合使用存储引擎吗?
尽量不要在同一个事务中使用多种存储引擎,回滚的时候会导致数据库不一致,每张表需要确定好自己的引擎
9. MySQL中是如何实现事务隔离的?
读未提交和串行化基本上是不需要考虑的隔离级别,前者不加锁限制,后者相当于单线程执行,效率太差。
MySQL 在可重复读级别解决了幻读问题,是通过行锁和间隙锁的组合 Next-Key 锁实现的。
详细原理看这篇文章:https://haicoder.net/note/MySQL
10. 什么是 MVCC?
MVCC, 即多版本并发控制。MVCC 的实现,是通过保存数据在某个时间点的快照来实现的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
锁
1. 为什么要加锁?
当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。
保证多用户环境下保证数据库完整性和一致性。
2.按照锁的粒度分数据库锁有哪些?(行,表,页)
在关系型数据库中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。
行级锁
- 行级锁是MySQL中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。
- 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
表级锁
- 表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。
- 开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。
页级锁
- 页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。BDB支持页级锁
- 开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
MyISAM和InnoDB存储引擎使用的锁:
- MyISAM采用表级锁(table-level locking)。
- InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁
3. 从锁的类别上分MySQL都有哪些锁呢?(共享锁和排他锁)
从锁的类别上来讲,有共享锁和排他锁。
- 共享锁: 又叫做读锁。 当用户要进行数据的读取时,对数据加上共享锁。共享锁可以同时加上多个。
- 排他锁: 又叫做写锁。 当用户要进行数据的写入时,对数据加上排他锁。排他锁只可以加一个,他和其他的排他锁,共享锁都相斥。
4. 数据库的乐观锁和悲观锁是什么?怎么实现的?
数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。
- 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。它是以一种预防的姿态在修改数据之前把数据锁住,然后再对数据进行读写,在它释放锁之前任何人都不能对其数据进行操作,直到前面一个人把锁释放后下一个人数据加锁,基本就是类似独占
- 乐观锁:乐观锁是对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁(这使得多个任务可以并行的对数据进行操作),只有到数据提交的时候才通过一种机制来验证数据是否存在冲突。实现方式:一般实现方式是通过加版本号然后进行版本号的对比方式实现。
两种锁的使用场景
从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。
5. 什么是死锁?怎么解决?
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。(资源请求达成一个环,谁也不能动)
常见的解决死锁的方法
1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。
2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;
如果业务处理不好可以用分布式事务锁或者使用乐观锁
6. 隔离级别与锁的关系
在读未提交级别下,无锁
在读已提交级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁;
在可重复读级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁。
可串行化是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。
7. 优化锁方面的意见?
- 使用较低的隔离级别
- 设计索引,尽量使用索引去访问数据,加锁更加精确,从而减少锁冲突
- 选择合理的事务大小,给记录显示加锁时,最好一次性请求足够级别的锁。列如,修改数据的话,最好申请排他锁,而不是先申请共享锁,修改时在申请排他锁,这样会导致死锁
- 不同的程序访问一组表的时候,应尽量约定一个相同的顺序访问各表,对于一个表而言,尽可能的固定顺序的获取表中的行。这样大大的减少死锁的机会。
- 尽量使用相等条件访问数据,这样可以避免间隙锁对并发插入的影响
- 不要申请超过实际需要的锁级别
- 数据查询的时候不是必要,不要使用加锁。MySQL的MVCC可以实现事务中的查询不用加锁,优化事务性能:MVCC只在committed read(读提交)和 repeatable read (可重复读)两种隔离级别
- 对于特定的事务,可以使用表锁来提高处理速度活着减少死锁的可能
分库分表
读写分离、主从同步
1. 什么是MySQL主从同步?
主从同步使得数据可以从一个数据库服务器复制到其他服务器上,在复制数据时,一个服务器充当主服务器(master),其余的服务器充当从服务器(slave)。
因为复制是异步进行的,所以从服务器不需要一直连接着主服务器,从服务器甚至可以通过拨号断断续续地连接主服务器。通过配置文件,可以指定复制所有的数据库,某个数据库,甚至是某个数据库上的某个表。
2. MySQL主从同步的目的?为什么要做主从同步?
- (主改,从读)通过增加从服务器来提高数据库的性能,在主服务器上执行写入和更新,在从服务器上向外提供读功能,可以动态地调整从服务器的数量,从而调整整个数据库的性能。
- (数据安全)提高数据安全-因为数据已复制到从服务器,从服务器可以终止复制进程,所以,可以在从服务器上备份而不破坏主服务器相应数据
- (从服务器分担计算,提高性能)在主服务器上生成实时数据,而在从服务器上分析这些数据,从而提高主服务器的性能
- 数据备份。一般我们都会做数据备份,可能是写定时任务,一些特殊行业可能还需要手动备份,有些行业要求备份和原数据不能在同一个地方,所以主从就能很好的解决这个问题,不仅备份及时,而且还可以多地备份,保证数据的安全
3. 如何实现MySQL的读写分离?
其实很简单,就是基于主从复制架构,简单来说,就搞一个主库,挂多个从库,然后我们就单单只是写主库,然后主库会自动把数据给同步到从库上去。