你不得不知道的MySQL知识点(一)

190 阅读6分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

引言

笔者最近在学习极客时间中的《MySQL实战45讲》,便写下此文,记录一些笔者认为需要掌握的知识点。本文将以问答的形式呈现,读者也可以通过查看目录标题来检验下自己是否掌握这些知识点。

MySQL基础架构是什么?

image.png

如上图所示,MySQL整体来说可以分来 Server 层和存储引擎层。

Server 层包括连接器、查询缓存、分析器、优化器和执行器等,不同存储引擎共享一个 Server 层。

存储引擎负责数据的存储和提取,其架构模式是插件式的,支持 InnoDB(最常用)、MyISAM 和 Memory 等多个存储引擎。

MySQL Server层各个组件有什么作用?

  • 连接器:负责跟客户端建立连接、获取权限、维持和管理连接。
  • 查询缓存:MySQL拿到一个查询请求后,会先到查询缓存查看是否执行过这个请求,如果命中缓存,则直接返回结果。
  • 分析器:对 SQL 语句进行解析,首先是词法分析,识别里面的字符串分别是什么,代表什么,比如 select 代表查询语句;然后做语法分析,判断 SQL 语句是否满足 MySQL 语法。如果这里识别到语句是 update 语句,则更新完之后会清空查询缓存
  • 优化器:在表里有多个索引的时候,决定使用哪个索引;或者在多表关联(join)的时候,决定各个表的连接顺序。
  • 执行器:调用存储引擎接口执行语句

简述一下MySQL的日志模块

MySQL 主要有两个日志模块:redo log(重做日志)和 binlog(归档日志)。

redo log

redo log 是 InnoDB 引擎特有的日志,记录的是“在某个数据页上做了什么修改”,是物理日志。

当有一条记录需要更新时,InnoDB 会将记录先写到 redo log,并更新内存,这个时候更新就算完成了。然后 InnoDB 会在系统比较空闲的时候将这个操作记录更新到磁盘里面。

redo log 是固定大小的,当写到末尾时会抹掉原本数据,进行循环写。

redo log 可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。

binlog

binlog 是 Server 层的日志,记录的是语句的原始逻辑,是逻辑日志。

binlog 有两种模式,statement 格式记录 sql 语句;row 格式会记录行的内容,记录两条,更新前和更新后都有。

binlog 可以追加写,文件写到一定大小后子切换到下一个,并不会覆盖以前的日志。

什么是两阶段提交

两阶段提交时为了保证 redo log 和 binlog 的逻辑一致,其流程如下所示:

  1. 假设当前执行某个操作,当写入 redo log 时,此时 redo log 会处于 prepare 状态,然后告知执行器执行完成,随时可以提交事务。
  2. 执行器生成此次操作的 binlog,并将 binlog 写入磁盘。
  3. 执行器调用引擎的提交事务接口将 redo log 修改成提交(commit)状态。

什么是事务

事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在 MySQL 中,事务支持是在引擎层实现的。

事务隔离级别有哪些

标准的事务隔离级别包括:读未提交(read uncommited)、读提交(read commited)、可重复读(repeatable read)和串行化。

  • 读未提交:是指一个事务还未提交时,它做的更改就能被其它事务看到。
  • 读提交:是指一个事务提交之后,它做的变更才会被其它事务看到。
  • 可重复读:是指一个事务执行过程中看到的数据,总是跟这个事务启动时看到的数据时一致的。同时,在该隔离级别下,未提交变更对其它事务也是不可见的。
  • 串行化:对于同一条记录,写会加写锁,读会加读锁。当出现读写锁冲突时,后访问的事务必须等前一个事务执行完成才能继续执行。

尽可能多地说下你对索引的理解

在 MySQL 中,索引是在存储引擎层实现的,以下将以 InnoDB 为例讲解索引。

索引的结构

在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,又因为 InnoDB 使用 B+ 树索引模型,所以数据都是存储在 B+ 树中。

每一个索引在 InnoDB 里面对应一棵 B+ 树。

假设有一个主键列为 ID 的表 T,表中有字段 k,k 上有索引。建表语句如下:

create table T(
id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;

则表 T 具有以下 B+ 树:

image.png

根据叶子结点的内容,索引类型分为主键索引(聚簇索引)和非主键索引(二级索引)。

主键索引叶子节点存储的是整行数据,非主键索引叶子节点内容是逐渐的值。

基于索引的查询

对于上面定义的表 T,有下面的查询语句:

  • 如果语句是 select * from T where ID=500,即主键查询,则只要搜索 ID 这棵 B+ 树。
  • 如果语句是 select * from T where k=5,即普通索引查询,则需要先搜索 k 索引树得到 ID,再使用 ID 到主键索引 B+ 树进行搜索。这个过程叫做回表。

为了避免回表(多扫描一颗索引树),应用中应该尽量使用主键查询。

索引的大小

索引是典型的空间换取时间的设计,显然,主键长度越小,普通索引的叶子结点就越小,普通索引占用的空间就越小。因此,从性能和存储空间考量,自增主键往往是更合理的选择。

覆盖索引

如果执行的语句是 select ID from T where k between 3 and 5,这时只需要查 ID 的值,而 ID 的值已经在 k 索引树上,因此可以直接提供结果,不需要回表。

简单来说,非主键索引(二级索引)覆盖了所有的查询需求,称为覆盖索引。 同理,select ID, k from T where k between 3 and 5 也满足覆盖索引的条件。

由于覆盖索引可以减少树的搜索次数,显著提升查询性能,因此使用覆盖索引事一个常用的性能优化手段。