001、MyISAM 和 InnoDB 区别?
- 是否支持行级锁 : MyISAM 只有表级锁(table-level locking),而 InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁。
- 是否支持事务和外键:MyISAM 不支持事务和外键,而 InnoDB 支持事务和外键。
- 是否支持 MVCC(多版本并发控制):仅 InnoDB 支持。应对高并发事务,MVCC 比单纯的加锁更高效;MVCC只在
READ COMMITTED
和REPEATABLE READ
两个隔离级别下工作;MVCC 可以使用乐观锁和悲观锁来实现;各数据库中 MVCC 实现并不统一。
对于 InnoDB 来说,如果你锁的那一列正好是索引列的话,那就使用行锁;如果不是索引列的话,那么就会退化为表锁。
002、什么是事务?事务的四大特性?
事务是逻辑上的一组操作,要么都执行成功,要么都不执行。
事务的四大特性:
- 原子性:指的是事务是最小的执行单元,不可分割。
- 一致性:执行事务后,数据库从一个正确的状态变化到另一个正确的状态。
- 隔离性:在并发访问数据库的时候,不同事务之间互不干扰。
- 持久性:一个事务被提交之后,它对数据库的改变是永久的,即使数据库发生故障,也不会对该事务的提交产生任何影响。
003、并发事务会带来哪些问题?
- 脏读:事务 A 访问一个数据并进行了修改,但这种修改还未提交到数据库,如果此时事务 B 也访问了这个数据,但由于事务 A 对改数据的修改还未提交,此时事务 B 访问到的数据是不正确的,这种情况就被称为脏读。
- 丢失修改:指的是事务 A 在读取一个数据后,在事务 A 提交前,事务 B 也读取了这个数据,事务 A 修改数据并提交后,事务 B 也修改数据并提交,此时事务 B 的修改覆盖了事务 A 的修改,也就是说事务 A 的修改丢失了。
- 不可重复读:事务 A 需要多次读取同一个数据,在两次读取该数据之间事务 B 访问并修改了该数据,那么事务 A 在前后两次读取到的数据是不一样的,这种现象就是不可重复读。
- 幻读:和不可重复读类似,事务 A 在读取了几行数据后,紧接着事务 B 又插入了一些数据,随后事务 A 再次进行查询就会发现一些原本不存在的记录,这种现象就是幻读。
不可重复读和幻读的区别:不可重复读的重点是修改,比如多次读取一条记录发现其中某些列的值被修改;幻读的重点在于新增或者删除,比如多次根据同一条件读取记录后发现记录增多或减少了。
004、事务的隔离级别有哪些?
- READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取还有变更未提交的数据,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生(InnoDB 在 RR 下可以解决幻读)。
- SERIALIZABLE(可串行化):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重复读)。
InnoDB 存储引擎在 **REPEATABLE-READ(可重读)事务隔离级别下使用的是 Next-Key 锁,因此可以避免幻读的产生,也就是说 InnoDB 存储引擎的默认支持的隔离级别REPEATABLE-READ(可重读)**已经可以完全保证事务的隔离性要求,即达到了 SQL 标准的 SERIALIZABLE(可串行化) 隔离级别。
005、表级锁和行级锁对比?
- 表级锁: MySQL 中锁定粒度最大的一种锁,对当前操作的整张表加锁,资源消耗少,加锁快,不会出现死锁,但并发度最低。
- 行级锁: MySQL 中锁定粒度最小的一种锁,只针对当前操作的行进行加锁,并发度高,但加锁的开销大,加锁慢,会出现死锁。
MyISAM 只支持表级锁;InnoDB 支持行级锁和表级锁,默认是行级锁。
InnoDB 在 sql 没有用到索引的时候用的是表级锁,在 sql 用到索引的时候用的是行级锁和间隙锁。
006、大表优化?
当 MySQL 单表数据量过大的时候,数据库的性能会明显下降,一些常见的优化措施如下:
- 限定数据的查询范围:如无必要,不要使用不带任何限制条件的查询语句。
- 读写分离:将数据库进行拆分,主库负责写,从库负责读。
- 垂直分区:将列较多的表根据列相关性拆分为多个表。优点是可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数,垂直分区可以简化表的结构,易于维护;缺点是主键会出现冗余,需要管理冗余列,并会引起 join 操作,可以通过在应用层进行 Join 来解决,垂直分区会让事务变得更加复杂。
007、分库分表之后 id 主键如何处理?
- UUID:不适合作为主键,因为太长了,并且无序不可读,查询效率低。比较适合用于生成唯一的名字的标示比如文件的名字。
- 数据库自增 id:两台数据库分别设置不同步长,生成不重复ID的策略来实现高可用。这种方式生成的 id 有序,但是需要独立部署数据库实例,成本高,还会有性能瓶颈。
- 利用 redis 生成 id:性能比较好,灵活方便,不依赖于数据库。但是,引入了新的组件造成系统更加复杂,可用性降低,编码更加复杂,增加了系统成本。
- 雪花算法
008、什么是索引?优缺点?
索引是一种用于快速查询和检索数据的数据结构。常见的索引结构有: B 树,B+ 树和 Hash。索引的作用就相当于目录的作用。
优点:极大地提高了数据的检索速度(大部分系统的读请求总是大于写请求的),通过创建唯一索引,还可以保证数据库表中每一行数据的唯一性。
缺点:创建索引和维护索引需要耗费许多时间,当对表中的数据进行增删改的时候,如果数据有索引,那么索引也需要动态的修改,会降低 SQL 执行效率;索引需要使用物理文件存储,也会耗费一定物理空间。
什么样的字段适合成为索引?
- 不为 NULL 的字段。索引字段的数据应该尽量不为 NULL,因为对于数据为 NULL 的字段,数据库较难优化。如果字段频繁被查询,但又避免不了为 NULL,建议使用 0,1,true,false 这样语义较为清晰的短值或短字符作为替代。
- 被频繁查询的字段。
- 被作为条件查询的字段。
- 被频繁用于连接的字段。经常用于连接的字段可能是一些外键列,对于外键列并不一定要建立外键,只是说该列涉及到表与表的关系。对于频繁被连接查询的字段,可以考虑建立索引,提高多表连接查询的效率。
不合适创建索引的字段?
频繁更新、不经常查询的字段一般不适合创建索引。
009、B 树和 B+ 树区别?
- B 树的所有节点既存放键(key)也存放数据(data);而 B+ 树只有叶子节点存放 key 和 data,其他内节点只存放 key。
- B 树的叶子节点都是独立的;B+ 树的叶子节点有一条引用链指向与它相邻的叶子节点。
- B 树的检索过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了;B+ 树的任何查找都是从根节点到叶子节点,然后在叶子节点内部进行顺序查找,查询效率稳定。
010、Hash 索引和 B+ 树索引优劣分析?
Hash 索引本质上就是哈希表,可以在很短的时间内通过哈希函数定位到数据所在的位置,但是缺点也很明显,无法用于排序,不支持范围查询,存在哈希冲突。
B+ 树是有序的,在进行范围查询时,有很大的优势,但在进行等值查询时效率不如 Hash 索引。