Innodb 不使用自增 id 作为主键存在的问题?
如果主键不是自增 id,每次新记录插入都要被插入到现有索引页中间某个位置,频繁移动、分页操作造成了大量碎片和不够紧凑的索引结构,后续不得不通过 optimize table 来重建表并优化填充页
Mysql 是如何执行一条 SQL 的
- 客户端请求
- 连接器(验证用户身份、给予权限)
- 查询缓存(存在缓存则直接返回,不存在则执行后续操作)
- 分析器(对 SQL 进行词法分析和语法分析操作)
- 优化器(执行计划生成、返回结果)
- 执行器(执行前看看用户是否有权限,有就调用接口)
- 去引擎层获取数据返回
数据库三大范式
- 第一范式:字段不可分
- 第二范式:有主键,非主键字段依赖主键
- 第三范式:非主键字段不能相互依赖
数据库索引采用 B+ 树而不是 B 树的原因是什么?
B+ 树只要遍历叶子结点就可以实现整棵树的遍历,在数据库中基于范围的查询是非常频繁的, B 树只能中序遍历所有节点,效率低
B+ 树索引、哈希索引和 B 树索引的区别?
B 树 叶子节点和非叶子节点都存储数据。 B+ 树 只有在叶子节点存储数据。 Hash 索引 哈新索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似 B+ 树那样从根节点到叶子节点逐级查找,只需一次哈希算法就能找到对应的位置。 哈希索引仅能满足等值查询,不能使用范围查询。
redo log 作用
mysql 为了提升性能,不会把每次修改的数据都实时同步到磁盘,会先存到 Buffer Pool,使用后台线程去做缓冲池和磁盘之间的同步
如果还没同步到磁盘的时候宕机或断电,可能会导致丢失部分已提交事务的修改信息。
所以引入了 redo log 来记录已成功提交事务的修改信息,并且会把 redo log 持久化到磁盘,系统重启之后读取 redo log 来恢复最新数据。
总结:redo log 是用来恢复数据的,用户保障已提交书事务的持久化特性
undo log 作用
undo log 记录事务修改之前版本的数据信息,加入由于系统错误或者 rollback 操作而回滚的话可以根据 undo log 的信息来进行回滚到之前没被修改前的状态。
总结:undo log 是用来回滚数据的,用户保证未提交事务的原子性
Select count(1) count(*) count(column)区别
性能方面 count(*) = count(1) > count(column),因为 count(column) 需要去判断 column 是否为空,多了一步判断的操作。
数据库 in用的了索引吗
事务中常见问题
-
脏读
事务 A 没有 commit,但是它的修改被事务 B 所看到。也就是说事务 B 读到了 事务 A 还没有提交的数据。这种行为被称为脏读,读到的数据是脏数据。
-
不可重复读
在事务 A 内,多次读取同一数据,每次读到的数据都不一样。叫作不可重复读。
-
幻读
事务 A 通过某些条件查询出一些记录,事务 B 又插入了符合这些条件的记录;事务 A 再次按照上次的某些条件进行数据查询,结果发现查询出来的数据发生变化,这就是幻读。
MVVC 实现原理
版本链
版本链就是一个链表,链接的是每条数据曾经的修改记录。版本链的实现主要依赖两个字段,分别是 trx_id 和 roll_pointer
一致性视图
一致性视图的作用就是用来判断版本链中哪些版本(trx_id)是当前事务可见的。其中有四个属性比较重要,分别是 m_ids、min_trx_id、max_trx_id、creator_trx_id,下面我们将分别讲讲这四个属性代表的含义是什么:
| 字段属性 | 含义 |
|---|---|
| m_ids | 在生成ReadView时,当前活跃的读写事务的事务id列表 |
| min_trx_id | m_ids的最小值 |
| max_trx_id | m_ids的最大值+1 |
| creator_trx_id | 生成该事务的事务id,单纯开启事务是没有事务id的,默认为0,creator_trx_id是0 |
知道了这 4 个字段的含义,那我们怎么判断版本链中的某一个版本的数据,当前事务可不可见呢?有以下几种情况,我们来分析一下:
- trx_id == creator_trx_id
当前事务可以看到自己修改的数据,所以是可见
- trx_id < min_trx_id
当前版本的数据在生成视图的时候就已经存在了,所以可见
- trx_id >= max_trx_id
当前版本的数据是在生成视图之后提交的,所以不可见
-
trx_id >= min_trx_id && trx_id < max_rx_id
- trx_id 在 m_ids 列表中,说明在生成视图的时候,该事务还没提交,处于活跃状态,所以不可见
- trx_id 不在 m_ids 列表中,说明在生成视图的时候,该事务已经提交了,所以可见

读提交(RC)每次 select 都会生成一个新的视图, 可重复读(RR)只在第一次 select 才会生成新的视图,后续的 select 不会再生成新的视图
可以这样理解,读提交,就是读到已经提交的数据,所以每次都需要生成一个新的视图。
Explain
-
extra
- Using Index: 覆盖索引
- Using where: 需要回表
- Using Index Condition:索引下堆
- Using filesort:磁盘排序
索引失效
- 以 % 开头的 like 语句,后缀 % 不影响
- or 前后没有同时使用索引, and 不影响
- 列类型是字符串,where 中一定要加引号,否则失效
- 在索引上使用 not , <>, != ,索引失效
两阶段提交
两阶段提交就是把一个事务分成两个阶段来提交
- 执行器想要更新记录 R
- InnoDB 将记录 R 加载进 Buffer Pool
- 将记录 R 的旧值写入 undo log ,便于回滚
- 执行器更新内存中的数据(此时该数据页为脏页)
- 执行器写 redo log (状态为 Prepare)
- 执行器写 binlog
- 执行器写 redo log (修改状态为 commit)
Mysql 怎么保证原子性
Mysql 是利用 innodb 的 undo log 来保证原子性的。例如
当你 delete 一条数据的数据,就需要记录这条数据的信息,回滚的时候,insert 这条旧数据。
undo log 记录了这些回滚需要的信息,当事务执行失败或调用了 rollback,导致事务回滚,便可以利用 undo log 中的信息将数据也回滚到修改之前的样子。
Mysql 是怎么保证持久性的
Mysql 是利用 innodb 的 redo log 来保证持久性的。Mysql 是先把磁盘上的数据加载到内存中,在内存中对数据进行修改,再刷回到磁盘上。如果此时突然宕机,内存中的数据就会丢失。
redo log 是怎么解决这个问题的
当数据修改的时候,不仅在内存中操作,还会在 redo log 中记录这次操作,当事务提交时,会将 redo log 日志进行刷盘。当数据库宕机重启的时候,会将 redo log 中的内容恢复到数据库中,再根据 undo log 和 binlog 内容决定回滚数据还是提交数据。
使用 redo log 的好处
好处就是将 redo log 刷盘比对数据页刷盘效率高,因为 redo log 体积小,并且每次都是往末尾追加,属于顺序 IO,效率比随机 IO 高。
Mysql 怎么保证隔离性
Mysql 利用锁 + MVCC 机制来保证隔离性。
Mysql 怎么保证一致性?
数据库通过原子性、隔离性、持久性来保证一致性。