Mysql 知识点

125 阅读6分钟

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_idroll_pointer

一致性视图

一致性视图的作用就是用来判断版本链中哪些版本(trx_id)是当前事务可见的。其中有四个属性比较重要,分别是 m_idsmin_trx_idmax_trx_idcreator_trx_id,下面我们将分别讲讲这四个属性代表的含义是什么:

字段属性含义
m_ids在生成ReadView时,当前活跃的读写事务的事务id列表
min_trx_idm_ids的最小值
max_trx_idm_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 怎么保证一致性?

数据库通过原子性、隔离性、持久性来保证一致性。