MySQL四十五讲(基础篇)知识汇总(全)

2023-10-28

MySQL四十五讲(基础篇)知识汇总(全)

根据极客时间 MySQL四十五讲 基础篇知识点汇总

认准 林晓斌老师
在这里插入图片描述

一、MySQL 基本架构

基本架构

  • 连接器:连接器负责跟客户端建立连接、获取权限、维持和管理连接
  • 查询缓存:之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查询的语句,value是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个 value 就会被直接返回给客户端。
  • 分析器:分析器先会做“词法分析”。你输入的是由多个字符串和空格组成的一条 SQL 语句,MySQL需要识别出里面的字符串分别是什么,代表什么。做完了这些识别以后,就要做“语法分析”。根据词法分析的结果,语法分析器会根据语法规则,判断你输入的这个SQL 语句是否满足 MySQL 语法。如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒
  • 优化器:优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序
  • 执行器:通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句,开始执行的时候,要先判断一下你对这个表T 有没有执行查询的权限,如果没有,就会返回没有权限的错误
  • 存储引擎: 存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据。不同的数据库管理系统支持多种不同的数据引擎,不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能。


MySQL 的核心就是存储引擎。

提示:InnoDB 事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键。MySQL 5.5.5 之后,InnoDB 作为默认存储引擎。



二、日志(Redo log 和 Binlog)

2.1 重要的日志模块 ----> Redo log

先把赊账的金额记录在粉板上,等不忙了再记录到账本

  • 粉板=“redo log”
  • 账本=“磁盘”

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

crash-safe

  • 赊账记录记在了粉板上或写在了账本上,之后即使掌柜忘记了,比如突然停业几天,恢复生意后依然可以通过账本和粉板上的数据明确赊账账目

2.2 重要的日志模块:Binlog

  • binlog 会记录所有的逻辑操作
  • 两阶段式提交

为了让数据在逻辑上一致

1.写入 redo log Prepare 阶段 – > 2.写入 binlog – > 3.Commit 提交


2.3 Redo log 与 Binlog 不同

  1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

redo log 用于保证 crash-safe 能力。innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候,表示每次事务的 redo log 都直接持久化到磁盘。这个参数我建议你设置成 1,这样可以保证 MySQL 异常重启之后数据不丢失。


sync_binlog 这个参数设置成 1 的时候,表示每次事务的 binlog 都持久化到磁盘。这个参数我也建议你设置成 1,这样可以保证MySQL 异常重启之后 binlog 不丢失。



三、 事务隔离

3.1 事务的特性

ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)

3.2 隔离级别

当数据库同时执行多个事务的时候 避免出现 脏读(dirty read)不可重复读(non-repeatable read)、**幻读(phantom read)**的问题。

SQL 标准的事务隔离级别:读未提交(read uncommitted)读提交(read committed)、可重复读(repeatable read)串行化(serializable )

  1. 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
  2. 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
  3. 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
  4. 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

Oracle 数据库的默认隔离级别其实就是“读提交”

3.2 事务隔离的实现

每条记录在更新的时候都会同时记录一条回滚操作。同一条记录在系统中可以存在多个版本,这就是数据库的多版本并发控制(MVCC)

举个例子:

在这里插入图片描述
如果这样的话,那么回滚日志肯定会很大,不过不用担心,

回滚日志会删除的!

那好 什么时候它会删除呢 ???

系统会判断当没有事务需要用到这些回滚日志的时候,回滚日志会被删除

那好 什么又是不需要的时候呢???

当系统里么有比这个回滚日志更早的 read-view 的时候

注意:尽量不要使用长事务

那好 这又是 为什么呢???

长事务意味着系统里面会存在很老的事务视图,在这个事务提交之前,回滚记录都要保留,这会导致大量占用存储空间。除此之外,长事务还占用锁资源,可能会拖垮库。

3. 4 事务启动方式

  1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
  2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select
    语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。

举个例子:
在这里插入图片描述
我们来看看在不同的隔离级别下,事务 A 会有哪些不同的返回结果,也就是图里面 V1、V2、V3 的返回值分别是什么。

  • 若隔离级别是“读未提交”, 则 V1 的值就是 2。这时候事务 B 虽然还没有提交,但是结果已经被 A 看到了。因此,V2、V3 也都是 2。
  • 若隔离级别是“读提交”,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以, V3 的值也是 2。
  • 若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。
  • 若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。


四、深入浅出索引(上)

4.1 索引作用及模型

索引的作用:提高数据查询效率
常见索引模型哈希表、有序数组、搜索树

4.1.1 哈希表

思路:

哈希表是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的值即 key,就可以找到其对应的值即 Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把 key 换算成一个确定的位置,然后把 value 放在数组的这个位置。

如何解决冲突:

多个 key 值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表。

在这里插入图片描述

实用场景:

哈希表这种结构适用于只有等值查询的场景




4.1.2 有序数组

思路:

有序数组:按顺序存储。查询用二分法就可以快速查询,时间复杂度是:O(log(N))
在这里插入图片描述

效率:

有序数组查询效率高,更新效率低

适用场景:

序数组索引只适用于静态存储引擎




4.1.3 二叉搜索树

思路:
每个节点的左儿子小于父节点,父节点又小于右儿子

在这里插入图片描述

时间复杂度:
查询时间复杂度 O(log(N)),更新时间复杂度 O(log(N))

数据库存储大多不适用二叉树,因为树高过高,会适用 N 叉树

注意:
数据库存储大多不适用二叉树,因为树高过高,会适用 N 叉树

4.2 InnoDB 的索引模型

4.2.1 索引类型

主键索引的叶子节点存的是整行数据 主键索引也被称为聚簇索引(clustered index)。

非主键索引的叶子节点内容是主键的值 非主键索引也被称为二级索引(secondary index)。

4.2.2 主键索引和普通索引的区别

主键索引只要搜索 ID 这个 B+Tree 即可拿到数据。普通索引先搜索索引拿到主键值,再到主键索引树搜索一次(回表)

基于非主键索引的查询需要多扫描一棵索引树

主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。

注意:

  • 一个数据页满了,按照 B+Tree 算法,新增加一个数据页,叫做页分裂,会导致性能下降。空间利用率降低大概 50%。当相邻的两个数据页利用率很低的时候会做数据页合并,合并的过程是分裂过程的逆过程。
  • 从性能和存储空间方面考量,自增主键往往是更合理的选择。



五、 深入浅出索引(下)

5.1 回表

再搜索的过程中 我们在非主键索引查询时,回到主键的过程 称之为 回表

5.2 覆盖索引

如果查询的数据可以直接提供结果,不需要回表,那么称之为 覆盖索引

 例如:select ID from T where k between 3 and 5

如果执行的语句是 select ID from T where k between 3 and 5,这时只需要查 ID 的值,而 ID的值已经在 k 索引树上了,因此可以直接提供查询结果,不需要回表。也就是说,在这个查询里面,索引 k 已经“覆盖了”我们的查询需求,我们称为覆盖索引。

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




六、 全局锁和表锁

6.1 全局锁

顾名思义,全局锁就是对整个数据库实例加锁

MySQL 提供了一个加全局读锁的方法,命令是

 Flush tables with read lock (FTWRL)

当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:

  • 数据更新语句(数据的增删改)、
  • 数据定义语句(包括建表、修改表结构等)
  • 更新类事务的提交语句

使用场景:
全局锁的使用场景典型是,做全库逻辑备份。也就是把整库每个表都 select 出来存成文本。

  • 如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆;
  • 如果你在从库上备份,那么备份期间从库不能执行主库同步过来的 binlog,会导致主从延迟。

6.2 表级锁

MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。

6.2.1 表锁

表锁的语法是

lock tables … read/write。

可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放。

在还没有出现更细粒度的锁的时候,表锁是最常用的处理并发的方式。
而对于 InnoDB 这种支持行锁的引擎 一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。

6.2.2 MDL:(元数据锁)

MDL 不需要显式使用,在访问一个表的时候会被自动加上

MDL 的作用是,保证读写的正确性。

  • 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。
  • 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

6.3 总结

全局锁主要用在逻辑备份过程中。对于全部是 InnoDB 引擎的库,我建议你选择使用–single-transaction 参数,对应用会更友好。

表锁一般是在数据库引擎不支持行锁的时候才会被用到的。如果你发现你的应用程序里有 lock tables 这样的语句,你需要追查一下,比较可能的情况是:

  • 要么是你的系统现在还在用 MyISAM 这类不支持事务的引擎,那要安排升级换引擎;
  • 要么是你的引擎升级了,但是代码还没升级。我见过这样的情况,最后业务开发就是把 lock tables 和 unlock tables 改成
    begin 和 commit,问题就解决了。

MDL 会直到事务提交才释放,在做表结构变更的时候,你一定要小心不要导致锁住线上查询和更新。




七、 行锁

7.1 什么是行锁?

行锁就是针对数据表中行记录的锁

解释:

比如事务 A 更新了一行,而这时候事务 B 也要更新同一行,则必须等事务 A 的操作完成后才能进行更新。

在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
在这里插入图片描述

当数据量大的时候 行锁就会造成锁的冲突,这个时候 我们就需要 来降低这个并发冲突

7.2 死锁和死锁检测

7.2.1 死锁

当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁

当出现死锁以后,有两种策略:

  • 一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout 来设置。
  • 另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。
7.2.2 死锁检测

首先 我们需要知道这个 : 死锁检测也是有额外负担的

那我们来举个例子说明一下:

每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁,这是一个时间复杂度是 O(n) 的操作。假设有 1000 个并发线程要同时更新同一行,那么死锁检测操作就是 100 万这个量级的。虽然最终检测的结果是没有死锁,但是这期间要消耗大量的 CPU 资源。因此,你就会看到 CPU 利用率很高,但是每秒却执行不了几个事务。

怎么解决由这种热点行更新导致的性能问题呢?

  • 一种头痛医头的方法,就是如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉。但是这种操作本身带有一定的风险,因为业务设计的时候一般不会把死锁当做一个严重错误,毕竟出现死锁了,就回滚,然后通过业务重试一般就没问题了,这是业务无损的。而关掉死锁检测意味着可能会出现大量的超时,这是业务有损的。
  • 另一个思路是控制并发度。根据上面的分析,你会发现如果并发能够控制住,比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很低,就不会出现这个问题。一个直接的想法就是,在客户端做并发控制。但是,你会很快发现这个方法不太可行,因为客户端很多。我见过一个应用,有 600 个客户端,这样即使每个客户端控制到只有 5 个并发线程,汇总到数据库服务端以后,峰值并发数也可能要达到 3000。



八、事务隔离

既然说到事务隔离 那么我们 首先得知道 MySQL是事务隔离的还是 不隔离的 对吧???

在 MySQL 里,有两个“视图”的概念:

  • 一个是 view。它是一个用查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果。创建视图的语法是 create view … ,而它的查询方法与表一样。
  • 另一个是 InnoDB 在实现 MVCC 时用到的一致性读视图,即 consistent read view,用于支持 RC(Read
    Committed,读提交)和 RR(Repeatable Read,可重复读)隔离级别的实现。

作用是事务执行期间用来定义 “我能看到什么数据”

8.1 “快照”在 MVCC 里是怎么工作的?

一致性视图:
在这里插入图片描述

这样,对于当前事务的启动瞬间来说,一个数据版本的 row trx_id,有以下几种可能:

  1. 如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;
  2. 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;
  3. 如果落在黄色部分,那就包括两种情况
    a. 若 row trx_id 在数组中,表示这个版本是由还没提交的事务生成的,不可见;
    b. 若 row trx_id 不在数组中,表示这个版本是已经提交了的事务生成的,可见。

所以这就是 为什么
系统里面随后发生的更新 就跟这个事务看到的内容无关了 而是去看版本

InnoDB 利用了“所有数据都有多个版本”的这个特性,实现了“秒级创建快照”的能力。

  1. 一个数据版本,对于一个事务视图来说,除了自己的更新总是可见以外,有三种情况: 版本未提交,不可见;
  2. 版本已提交,但是是在视图创建后提交的,不可见;
  3. 版本已提交,而且是在视图创建前提交的,可见。

8.2 更新逻辑

更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)。

读提交的逻辑和可重复读的逻辑类似,它们最主要的区别是:

  • 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;
  • 在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。

8.3 总结:

InnoDB 的行数据有多个版本,每个数据版本有自己的 row trx_id,每个事务或者语句有自己的一致性视图。普通查询语句是一致性读,一致性读会根据 row trx_id 和一致性视图确定数据版本的可见性。

  • 对于可重复读,查询只承认在事务启动前已经提交完成的数据;
  • 对于读提交,查询只承认在语句启动前已经提交完成的数据;

而当前读,总是读取已经提交完成的最新版本。




基础篇发布完毕 稍后 会更新 实践篇

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL四十五讲(基础篇)知识汇总(全) 的相关文章

随机推荐

  • 【华为OD机试真题 C++】简易压缩算法

    前言 本专栏将持续更新华为OD机试题目 并进行详细的分析与解答 包含完整的代码实现 希望可以帮助到正在努力的你 关于OD机试流程 面经 面试指导等 如有任何疑问 欢迎联系我 wechat steven moda email nansun09
  • VS2019运行慢的解决方法

    说一下我的办法 从网上找的 废老大劲了 1 工具 选项 intellitrace 把启用那个勾取消 2 工具 选项 文本编辑器 C C 高级 代码分析 禁用后台代码分析 改为true 3 工具 选项 文本编辑器 所有语言 滚动条 行为 选择
  • 一个简单的工具类 日志合并成块打印

    场景 日志需要跨方法甚至跨类打印 又想让一个线程的打印可以按顺序成块打印 例 如HttpUtil工具类发起工具类 public String postForm String url HttpForm param log info 请求开始
  • 你不知道的JavaScript-----对象

    目录 语法 类型 内容 属性 属性访问的方式 可计算属性名 数组 复制对象 属性描述符 不变性 定义常量 defineProperty 禁止扩展 preventExtensions Object seal 会创建一个 密封 的对象 Obje
  • IDA 介绍和使用

    文章目录 一 IDA 介绍 二 IDA使用 一 IDA 介绍 IDA的新手入门指南 IDA的反编译插件hexrays decompiler 逆向分析工具IDA与开源工具Ghidra Cutter对比测评 IDA Interactive Di
  • CSS毛玻璃效果

    文章目录 一 css毛玻璃效果 1 原图 2 效果图 3 代码展示 总结 提示 以下是本篇文章正文内容 下面案例可供参考 一 css毛玻璃效果 1 原图 2 效果图 3 代码展示 代码如下 示例
  • SSAS的入门介绍

    一 是什么 SSAS是用于SQLServer数据库用于BI的组件 通过SSAS可以创建多维数据库 并在之上进行数据挖掘操作 本文我们主要介绍一些关于SSAS数据分析的知识 接下来就让我们来一起了解一下吧 商业智能提供的解决方案能够从多种数据
  • 数组的度——哈希表与滑动窗体法的实践

    一 题目 给定一个非空且只包含非负数的整数数组 nums 数组的度的定义是指数组里任一元素出现频数的最大值 你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组 返回其长度 二 哈希表法解析 记原数组中出现次数最多的
  • 回溯递归(例题+思路+代码)

    题目描述 leetcode 77 思路 组合问题适合用回溯求解 经典解法 for循环 内部回溯 每次进入回溯方法时 先判断终止条件 再进行当前层的循环 循环进行下一层递归 代码 class Solution public List
  • C语言——输入三位整数并输出最大值

    利用整形变量 进行定义 进行if语句比较赋最大值 include
  • MybatisPlus简介,特点,快速入门,常用方法

    MyBatisPlus MyBatis Plus opens new window 简称 MP 是一个 MyBatis opens new window 的增强工具 在 MyBatis 的基础上只做增强不做改变 为简化开发 提高效率而生 特
  • numpy中矩阵的翻转(flip)

    numpy flip m axis None Reverse the order of elements in an array along the given axis The shape of the array is preserve
  • 保姆级使用PyTorch训练与评估自己的MobileViT网络教程

    文章目录 前言 0 环境搭建 快速开始 1 数据集制作 1 1 标签文件制作 1 2 数据集划分 1 3 数据集信息文件制作 2 修改参数文件 3 训练 4 评估 5 其他教程 前言 项目地址 https github com Fafa D
  • angular引入ng-zorro的方法

    安装ng zorro组件 npm install ng zorro antd save 导入模块 import NgZorroAntdModule from ng zorro antd imports BrowserModule NgZor
  • 【2023】华为OD机试真题Java-题目0210-优秀学员统计

    优秀学员统计 题目描述 公司某部门软件教导团正在组织新员工每日打卡学习活动 他们开展这项学习活动已经一个月了 所以想统计下这个月优秀的打卡员工 每个员工会对应一个id 每天的打卡记录记录当天打卡员工的id集合 一共30天 请你实现代码帮助统
  • ajax 筛选表格内容,基于jquery实现表格内容筛选功能实例解析

    当表格内的数据较多时 我们无法一页一页的查找 这时可以通过一个搜索框来实现搜索 对于这个搜素框 我们为了更好的体验可以利用keyup事件实现在用户输入的时候就开始筛选 而不是填完以后点击搜索按钮再执行 效果图 实现代码 function t
  • HNU-电路与电子学-学习笔记(12~24讲)

    放一下12讲 24讲的笔记吧 其它部分的笔记不全 就不放了 每一讲都是我在结合了课本内容 上课PPT 上课笔记后自己总结的知识点 电路与电子学算是我学得最认真的一门课了 最后也取得了还算满意的成绩 希望能够帮助到有需要的同学
  • Vue项目中你是如何解决跨域的呢?

    一 跨域是什么 跨域本质是浏览器基于同源策略的一种安全手段 同源策略 Sameoriginpolicy 是一种约定 它是浏览器最核心也最基本的安全功能 所谓同源 即指在同一个域 具有以下三个相同点 协议相同 protocol 主机相同 ho
  • 工具篇——Base64FileUtil(将文件转成base64 字符串)

    写代码的四点 1 明确需求 要做什么 2 分析思路 要怎么做 1 2 3 3 确定步骤 每一个思路要用到哪些语句 方法和对象 4 代码实现 用具体的语言代码将思路实现出来 学习新技术的四点 1 该技术是什么 2 该技术有什么特点 使用需注意
  • MySQL四十五讲(基础篇)知识汇总(全)

    MySQL四十五讲 基础篇 知识汇总 全 一 MySQL 基本架构 二 日志 Redo log 和 Binlog 2 1 重要的日志模块 gt Redo log 2 2 重要的日志模块 Binlog 2 3 Redo log 与 Binlo