暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL 高频八股

程序员恰恰 2024-04-05
70


  • 1、三大范式
  • 2、SQL 语句在 MySQL 内部执行流程。
  • 3、MyISAM 和 InnoDB 有什么区别?
  • 4、redo log 了解吗?
  • 5、redo log 的刷盘时机
  • 6、redo log 是怎么记录日志的
  • 7、什么是 binlog
  • 8、binlog 记录格式
  • 9、binlog 写入机制
  • 10、redolog 和 binlog 的区别是什么
  • 11、两阶段提交
  • 12、什么是 undo log.
  • 13、什么是 relaylog
  • 14、简单描述 MySQL 中,索引,主键,唯一索引,联合索引的区别?
  • 15、数据库中的事务是什么?
  • 16、聚簇索引与非聚簇索引
  • 17、聚簇索引与非聚簇索引
  • 18、索引哪些情况会失效

1、三大范式

第一范式: 属性不可再分.
第二范式: 在一范式的基础上, 要求数据库表中的每个实例或行必须可以被惟一地区分. 通常需要为
表加上一个列, 以存储各个实例的惟一标识. 这个惟一属性列被称为主关键字或主键.
第三范式: 在二范式的基础上, 要求一个数据库表中不包含已在其它表中已包含的非主关键字信息.
所以第三范式具有如下特征:1). 每一列只有一个值. 2). 每一行都能区分. 3). 每一个表都不包含其
他表已经包含的非主关键字信息.
2、一条 SQL 语句在 MySQL 内部是如何执行的。
  • 连接器: 身份认证和权限相关(登录 MySQL 的时候)。
  • 查询缓存: 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。
  • 分析器: 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。
  • 优化器: 按照 MySQL 认为最优的方案去执行。
  • 执行器: 执行语句,然后从存储引擎返回数据。执行语句之前会先判断是否有权限,如果没有权限的话,就会报错。
  • 插件式存储引擎:主要负责数据的存储和读取,采用的是插件式架构,支持 InnoDB、MyISAM、Memory 等多种存储引擎。


3、MyISAM 和 InnoDB 有什么区别?

  • InnoDB 支持事务,MyISAM 不支持事务

  • InnoDB 支持外键,MyISAM 不支持外键

  • InnoDB 支持 MVCC(多版本并发控制)MyISAM 不支持

  • select count(*) from table 时,MyISAM 更快,因为它有一个变量保存了整个

  • 表的总行数,可以直接读取,InnoDB 就需要全表扫描。

  • Innodb 不支持全文索引,而 MyISAM 支持全文索引(5.7 以后的 InnoDB 也支持全文索引)

  • InnoDB 支持表、行级锁,而 MyISAM 支持表级锁。

  • InnoDB 表必须有主键,而 MyISAM 可以没有主键

  • Innodb 表需要更多的内存和存储,而 MyISAM 可被压缩,存储空间较小,。

  • Innodb 按主键大小有序插入,MyISAM 记录插入顺序是,按记录插入顺序保存。

  • InnoDB 存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全,与

  • MyISAM InnoDB 写的效率差一些,并且会占用更多的磁盘空间以保留数据和索引

4、redo log 了解吗?
redo log
(重做日志)是InnoDB
存储引擎独有的,它让MySQL
拥有了崩溃恢复能力。
比如 MySQL
实例挂了或宕机了,重启时,InnoDB
存储引擎会使用redo log
恢复数据,保证数据的持久性与完整性。
更新表数据的时候,如果发现 Buffer Pool
里存在要更新的数据,就直接在 Buffer Pool
里更新。然后会把“在某个数据页上做了什么修改”记录到重做日志缓存(redo log buffer
)里,接着刷盘到 redo log
文件里。

5、redo log 的刷盘时机


  • 红色部分为 redo log buffer 属于内存
  • 黄色部分为 page cache ,此时已经写入磁盘了,但是未进行持久化
  • 绿色部分是硬盘,已经完成持久化
InnoDB 存储引擎为 redo log 的刷盘策略提供了 innodb_flush_log_at_trx_commit 参数,它支持三种策略
  • 设置为0的时候,表示每次事务提交时不进行刷盘操作,只是保留在 redo log buffer中,mysql 崩溃会丢失1s的数据;
  • 设置为1的时候,表示每次事务提交时都将进行刷盘操作(默认值),持久化到磁盘;
  • 设置为2的时候,表示每次事务提交时都只把redo log buffer内容写入page cache,OS宕机会丢失1s的数据,因为未进行持久化;
innodb_flush_log_at_trx_commit 参数默认为 1 ,也就是说当事务提交时会调用 fsync(同步操作) 对 redo log 进行刷盘。
另外 InnoDB 存储引擎有一个后台线程,每隔1秒,就会把 redo log buffer 中的内容写到文件系统缓存(page cache),然后调用 fsync 刷盘。
redo log buffer占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘。

6、redo log 是怎么记录日志的

硬盘上存储的 redo log
日志文件不只一个,而是以一个日志文件组的形式出现的,每个的redo
日志文件大小都是一样的。
比如可以配置为一组4
个文件,每个文件的大小是 1GB
,整个 redo log
日志文件组可以记录4G
的内容。
它采用的是环形数组形式,从头开始写,写到末尾又回到头循环写,如下图所示。
所以,如果数据写满了但是还没有来得及将数据真正的刷入磁盘当中,那么就会发生「内存抖动」现象,从肉眼的角度来观察会发现 mysql 会宕机一会儿,此时就是正在刷盘了。

7、什么是 binlog

binlog 是归档日志,属于 Server 层的日志,是一个二进制格式的文件,记录内容是语句的原始逻辑,类似于“给 ID=2 这一行的 c 字段加 1”。

不管用什么存储引擎,只要发生了表数据更新,都会产生 binlog
日志。它的主要作用就是数据备份、主从复制。

binlog
会记录所有涉及更新数据的逻辑操作,属于逻辑日志,并且是顺序写。

8、binlog 记录格式

binlog
日志有三种格式,可以通过binlog_format
参数指定。
  • statement :记录的内容是SQL
    语句原文,存在数据一致性问题;
  • row:记录包含操作的具体数据,能保证同步数据的一致性;
  • mixed:记录的内容是前两者的混合,MySQL
    会判断这条SQL
    语句是否可能引起数据不一致:如果是,就用row
    格式,否则就用statement
    格式。

9、binlog 写入机制

事务执行过程中,先把日志写到binlog cache
,事务提交的时候,再把binlog cache
写到binlog
文件中。
因为一个事务的binlog
不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache
我们可以通过binlog_cache_size
参数控制单个线程 binlog cache 大小,如果存储内容超过了这个参数,就要暂存到磁盘(Swap
)。
binlog 也提供了 sync_binlog 参数来控制写入 page cache 和磁盘的时机:
  • 0:每次提交事务都只写入到文件系统的 page cache,由系统自行判断什么时候执行fsync
    ,机器宕机,page cache
    里面的 binlog 会丢失。
  • 1:每次提交事务都会执行fsync
    ,就如同 redo log 日志刷盘流程 一样。
  • N(N>1):每次提交事务都写入到文件系统的 page cache,但累积N
    个事务后才fsync
    。如果机器宕机,会丢失最近N
    个事务的binlog
    日志。

10、redolog 和 binlog 的区别是什么

  • redologInnodb 独有的日志,而 binlogserver 层的,所有的存储引擎都有使用到;
  • redolog 记录了具体的数值,对某个页做了什么修改,binlog 记录的操作内容
  • binlog 大小达到上限或者 flush log 会生成一个新的文件,而 redolog 有固定大小只能循环利用
  • binlog 日志没有 crash-safe 的能力,只能用于归档,而 redo log 有 crash-safe 能力;
  • redo log 在事务执行过程中可以不断写入(刷盘设置为1,后台线程1s执行一次或者 redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候),而 binlog 只有在提交事务时才写入文件缓存系统;

11、两阶段提交

假设执行 sql 过程中写完 redo log 日志后,binlog 日志写期间发生了异常,会出现什么情况呢?
由于 binlog 没写完就异常,这时候 binlog 里面没有对应的修改记录。因此,之后用 binlog 日志恢复数据时,就会少这一次更新,最终数据不一致
为了解决两份日志之间的逻辑一致问题,InnoDB 存储引擎使用两阶段提交方案。
将 redo log 的写入拆成了两个步骤 prepare 和 commit,这就是两阶段提交。使用两阶段提交后,写入 binlog 时发生异常也不会有影响,因为 MySQL 根据 redo log日志恢复数据时,发现 redo log 还处于 prepare 阶段,并且没有对应 binlog 日志,就会回滚该事务。
再看一个场景,redo log 设置 commit 阶段发生异常,那会不会回滚事务呢?
并不会回滚事务,虽然 redo log 是处于 prepare 阶段,但是能通过事务id找到对应的 binlog 日志,所以 MySQL 认为是完整的,就会提交事务恢复数据。

12、什么是 undo log.

我们知道如果想要保证事务的原子性,就需要在异常发生时,对已经执行的操作(INSERT、DELETE、UPDATE)进行回滚,在 MySQL 中,恢复机制是通过回滚日志(undo log) 实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后再执行相关的操作。
每次对记录进行改动都会记录一条 undo log,每条 undo log 也都有一个DB_ROLL_PTR
属性,可以将这些 undo log 都连起来,串成一个链表,形成版本链。
版本链的头节点就是当前记录最新的值。

13、什么是 relaylog

relaylog 是中继日志,在主从同步的时候使用到,它是一个中介临时的日志文件,用于存储从 master 节点同步过来的 binlog 日志内容。
master 主节点的 binlog 传到 slave 从节点后,被写入 relay log 里,从节点的 slave sql 线程从 relaylog 里读取日志然后应用到 slave 从节点本地。
从服务器 I/O 线程将主服务器的二进制日志读取过来记录到从服务器本地文件,然后 SQL 线程会读取 relay-log 日志的内容并应用到从服务器,从而使从服务器和主服务器的数据保持一致
14、简单描述 MySQL 中,索引,主键,唯一索引,联合索引的区别?
索引:是一种特殊的文件(InnoDB 数据表上的索引是表空间的一个组成部分), 它们包含着对数据表里所有记录的引用指针。
普通索引:(由关键字 KEY 或 INDEX 定义的索引)的唯一任务是加快对数据的访问度。普通索引允许被索引的数据列包含重复的值。如果能确定某个数据列将只包含彼此各不相同的值, 在为这个数据列创建索引的时候就应该用关键字 UNIQUE 把它定义为一个唯一索引。也就是说, 唯一索引可以保证数据记录的唯一性。
主键: 是一种特殊的唯一索引, 在一张表中只能定义一个主键索引, 主键用于唯一标识一条记录, 使用关键字 PRIMARY KEY 来创建。
索引可以覆盖多个数据列,如像 INDEX(columnA, columnB)索引,这就是联合索引。
索引可以极大的提高数据的查询速度, 但是会降低插入、删除、更新表的速度, 因为在执行这些写操作时, 还要操作索引文件。
15、数据库中的事务是什么?
事务( transaction) 是作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功, 则认为
事务成功, 即使只有一个操作失败, 事务也不成功。如果所有操作完成, 事务则提交, 其修改将作用
于所有其他数据库进程。如果一个操作失败, 则事务将回滚, 该事务所有操作的影响都将取消。
事务特性:
1、原子性:即不可分割性, 事务要么全部被执行, 要么就全部不被执行。
2、一致性或可串性。事务的执行使得数据库从一种正确状态转换成另一种正确状态
3、隔离性。在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务,
4、持久性。事务正确提交后, 其结果将永久保存在数据库中, 即使在事务提交后有了其他故障, 事
务的处理结果也会得到保存。或者这样理解:事务就是被绑定在一起作为一个逻辑工作单元的 SQL 语
句分组, 如果任何一个语句操作失败那么整个操作就被失败, 以后操作就会回滚到操作前状态, 或者
是上有个节点。为了确保要么执行, 要么不执行, 就可以使用事务。要将有组语句作为事务考虑, 就
需要通过 ACID 测试, 即原子性, 一致性, 隔离性和持久性。
16、聚簇索引与非聚簇索引
聚簇索引即索引结构和数据一起存放的索引,并不是一种单独的索引类型。InnoDB 的主键索引的叶子节点中存放的就是数据行,所以它属于聚簇索引。
在 MySQL 中,InnoDB 引擎的表的 .ibd 文件就包含了该表的索引和数据,对于 InnoDB 引擎表来说,该表的索引(B+树)的每个非叶子节点存储索引,叶子节点存储索引和索引对应的数据。
非聚簇索引即索引结构和数据分开存放的索引,并不是一种单独的索引类型。二级索引(辅助索引)就属于非聚簇索引。MySQL 的 MyISAM 引擎,不管主键还是非主键,使用的都是非聚簇索引。
辅助索引是我们人为创建的索引,它的叶子节点中存放的是主键,当我们通过辅助
索引查找到主键之后,再通过查找的主键去回表查找主键索引。

17、索引哪些情况会失效

  • 查询条件包含 or,可能导致索引失效(or两边的条件都是索引才行)

  • 如何字段类型是字符串,where 时一定用引号括起来,否则索引失效

  • like 通配符可能导致索引失效。

  • 联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。

  • 在索引列上使用 mysql 的内置函数,索引失效。

  • 对索引列运算(如,+、-、*、/),索引失效。

  • 索引字段上使用(!= 或者 < >,not in)时,可能会导致索引失效。

  • 索引字段上使用 is null, is not null,可能导致索引失效。

  • 左连接查询或者右连接查询查询关联的字段编码格式不一样,可能导致索引失效。

  • mysql 估计使用全表扫描要比使用索引快,则不使用索引。

18、索引不适合哪些场景

  • 数据量少的不适合加索引

  • 更新比较频繁的也不适合加索引

  • 区分度低的字段不适合加索引(如性别)


---THE END---




文章转载自程序员恰恰,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论