MySQL相关知识点梳理

一、MySQL架构

  • 连接层:处理连接,身份验证等。
  • 核心服务层:包含权限判断、查询缓存、解析器、查询优化器、执行引擎等。
  • 存储引擎层:负责管理数据的底层组件,定义了如何存储、索引和检索数据。
  • 数据存储层:与文件系统进行交互完成数据读写。

二、数据库引擎

  • InnoDB: 支持事务;支持行锁;范围查询速度更快;支持外键;数据备份通过binlog,binlog存储的是一个库中所有表中的数据,只能整个库备份,数据量大时备份和恢复麻烦;索引通过B+树和hash实现。
  • MyISAM: 不支持事务;仅支持表锁;范围查询相对较慢;不支持外键;每个表都有独立的三个文件存储,备份和恢复可以针对单个表进行;索引基于B树实现。
  • 想要进一步理解的小伙伴欢迎阅读另一篇文章《MySQL数据库引擎》

三、MySQL事务

  • 概念: 一系列操作要么全部执行完成,要么全部失败回滚,保证数据一致性和完整性。

  • 特性(ACID):

    • 原子性(Atomicity):构成事务的一批指令要么全部执行成功,要么全部执行失败。
    • 一致性(Consistency):事务执行前后数据一致。
    • 隔离性(Isolation):多个事务间相互隔离。
    • 持久性(Durability):事务提交后,执行结果会持久化到磁盘。
  • 数据库事务隔离级别:

    • 读未提交:一个事务可以读取到另一个事务未提交的数据。该隔离级别下,可能出现赃读、幻读、不可重复读。
    • 读已提交: 一个事务仅能读取到另一个事务已提交的数据,未提交的数据不允许访问。Oracle默认的事务隔离级别。 该隔离级别下,可能出现幻读、不可重复读。
    • 可重复读: 一个事务中多次进行相同的读取,结果不发生改变。MySQL默认的事务隔离级别。 该隔离级别下,可能出现幻读。
    • 串行化:一个事务在操作数据库时,其他事务只能排队等待。这种隔离级别很少使用,吞吐量太低,用户体验很差。
  • 数据库事务隔离级别可能导致的问题:

    • 赃读:读取到另一个事务未提交的数据。
    • 不可重复读:同一事务进行多次相同的读取,读取结果不一致。
    • 幻读: 一个事物根据条件查询到满足条件的数据,但该事务未提交时,其他事务写入了其他符合条件的数据,导致查出的数据和预期不符。
  • 为什么一般使用读已提交而不是可重复读?

    • ①读已提交,可以读取到事务已提交的数据,大部分场景下都是可以接受的。
    • ②读已提交使用短暂行锁和快照读(MVCC)解决并发问题,可重复读使用行锁、间隙锁和快照读(MVCC)解决并发问题,出现死锁的概率更大。
    • ③未命中索引,读已提交隔离级别会使用行锁,可重复读隔离级别会使用表锁,读已提交隔离下的并发性能更好。
  • 行锁、间隙锁与临键锁:

    • 行锁: 针对主键或者唯一索引显示加锁的时候,MySQL默认会对查询的这一行数据加行锁,避免其他事务对这一行数据修改。例如:

      sql 复制代码
      select * from table where id = 1 for update;
    • 间隙锁: 锁定一个左右开区间范围。B+树索引,基于索引列的范围查询,无论是否是唯一索引,都会触发间隙锁。例如:

      sql 复制代码
      select * from table where id between 5 and 7 for update;
    • 临键锁: 使用非唯一索引进行查询,默认会叫一个临键锁,锁定一个左开右闭的区间。例如:

      sql 复制代码
      -- 临键锁,锁定区间(前一条数据值,11]
      select * from table where age = 11 for update;
  • 想要进一步理解的小伙伴欢迎阅读另一篇文章《MySQL事务》

四、分布式事务

  • 事务消息: 可以视作两阶段提交实现,保证分布式系统中的最终一致性。但由于事务消息具有异步特性,调用方拿不到消费方的处理结果,所以适用于不关心处理结果或者消费方保证消息处理成功的场景。kafka、rocketmq都支持事务消息。
  • 事务消息的执行流程:
    • 1.MQ生产者发送消息到服务器端;
    • 2.服务器端确认收到消息,但消息不会立即发送给消费者;
    • 3.执行本地事务;
    • 4.根据本地事务的执行结果,通知MQ服务器端提交或回滚(丢弃)消息;
    • 5.消费者处理消息。
  • TCC:
    • ①Try:完成所有业务检查,并预留业务资源;
    • ②Confirm:确认业务执行,提交事务,不做任何业务检查,只使用Try阶段预留的业务资源,操作必须保证幂等性;
    • ③Cancel:取消执行业务操作,释放Try阶段预留的业务资源,操作需要满足幂等性。
  • 与二阶段提交相比,二阶段提交是DB层面的,TCC是业务层面的。TCC的优点:灵活定义粒度,降低锁冲突;缺点:代码侵入性强,需要保证幂等性,需要根据不同的异常定义不同的回滚策略,代码复杂度增加。
  • 二阶段提交: 经典的分布式事务协议,用于确保分布式事务的一致性。
    • 准备阶段:协调者向所有参与者发送事务准备请求,参与者收到后,执行事务但不提交,成功后通知协调者准备就绪。
    • 提交阶段:如果所有参与者都准备就绪,协调者发送提交请求,参与者收到请求后提交事务,释放资源;如果存在未准备就绪或异常的参与者,回滚并释放资源。
    • 实际使用时一般会考虑更高效的分布式事务协议,三阶段提交 或者消息队列的事务消息,以减少阻塞时间和单点故障影响。
  • 三阶段提交:
    • ① 协调者问询是否可以提交事务。如果所有参与者都准备好提交事务,则进行第二阶段;如果任何一个参与者无法提交,协调者直接进入第三阶段。
    • ② 协调者要求参与者预提交事务,并等待参与者确认。参与者执行事务的预提交操作,但不释放资源。
    • ③ 最终提交事务并释放资源。 如果有任何一个参与者未成功提交,回滚整个事务。
  • saga模式: 将一个大事务拆分成多个小事务,每个小事务都有自己的补偿操作。相对于传统的分布式事务解决方案(如二阶段提交),saga模式更适合复杂的微服务架构,能够提供更好的伸缩性和容错性。

五、MySQL中的各类log文件

  • redolog: 重做日志,InnoDB引擎下,对数据进行增删改操作,会先将增删改记录写入redolog,然后系统空闲时根据策略(①事务提交时刷盘②定期刷盘③文件达到一定大小时刷盘)将redolog中的数据刷新到磁盘中。作用: 事务执行过程中异常宕机,数据库可以通过redolog恢复数据,保证数据一致性和持久性。
  • undolog: 撤销日志,用于存储数据被修改前的值,会存储多个旧版本的数据,如果事务执行异常,可以使用undolog中的数据进行回滚,保证事务的原子性和一致性;也被用于实现MVCC多版本并发控制。
  • binlog: 二进制日志,用于数据备份,数据恢复,主从同步。

六、MVCC

  • MVCC: 多版本并发控制,通俗讲就是数据库中同时存在多个版本的数据,在某个事务进行操作时,会根据事务隔离级别和各版本数据隐藏列中的事务ID决定读取哪个版本的数据。读已提交和可重复读事务隔离级别都有基于MVCC进行实现。
  • 隐藏列: InnoDB引擎下,每一行数据都有两个隐藏字段,trx_id(事务ID)和roll_pointer(指向undolog中上一个版本记录的ID,会形成一个版本链);如果表中没有主键或非NULL唯一键时,还会有一个隐藏字段row_id。
  • 快照读: 读取记录数据的可见版本,包含旧版本;不会加锁,普通的select语句都是快照读。
  • 当前读: 读取记录数据的最新版本,显式加锁都是当前读(for update)。
  • MVCC流程:
    • ① 获取当前事务的版本号trx_id;
    • ② 获取读视图;
    • ③ 根据条件匹配数据,然后读视图中的事务版本号进行比较;
    • ④ 如果不符合读视图的可见性规则,则使用undolog中的历史快照再次进行可见性判断;
    • ⑤ 最后返回符合可见性规则的数据。
  • Read View(读视图): 事务执行SQL时产生的读视图,主要用于可见性判断。
    • 几个重要属性:creator_id(创建当前读视图的事务ID),min_limit_id(生成读视图时,活跃的最小事务ID),max_limit_id(生成读视图时,系统应该分配给下一个事务的事务ID),m_ids(生成读视图时,当前活跃未提交的读写事务ID集合) 。
    • 可见性判断规则:
      • ① 如果记录事务ID小于生成读视图时活跃的最小事务ID,则说明该版本记录的事务在生成读视图前已经提交,可以被当前事务访问;
      • ② 如果记录事务ID大于等于生成读视图时系统该分配给下一个事务的事务ID,说明该版本记录的事务在生成读视图后,不能被当前事务访问;
      • ③ 如果记录事务ID等于创建读视图的事务ID,说明该版本记录是当前事务生成的数据,可见;
      • ④ 如果记录事务ID不等于创建读视图的事务ID,且在生成读视图时当前活跃未提交的读写事务ID集合中,说明该版本记录在生成读视图时还未提交,不可见。
      • ⑤如果记录事务ID大于等于活跃的最小事务ID,小于下一个事务的事务ID,且未在活跃事务集合中,同时不为创建视图的事务ID,说明事务已经提交,可见。

七、分库分表

  • 分库
    • 为什么分库? ①降低磁盘存储压力;②单数据库连接数有最大限制,分库可以提高并发连接数。
    • 何时分库? ①预估单库数据量5000W以上时可以考虑分库,实际场景根据服务器配置会有波动;②并发连接数很高时,可以将核心业务与边缘业务的数据库拆分开。
    • 如何分库? 水平拆分、垂直拆分。
    • 分库分表后如何解决join问题? 字段冗余,基础数据做全局表,数据汇总到一张表或者ES,应用层进行组装等。
    • 分库分表后事务问题如何解决? 分布式事务,如事务消息、二阶段提交、三阶段提交、TCC、分布式事务saga模式等。
  • 分表: 将单个表中的数据按照某种规则拆分到多个表中,可以提高查询性能、降低单表数据量过大的压力,但是会增加技术复杂度。
    • 为什么分表? 单表数据量过大,性能陷入瓶颈。单表数据量达到千万级(500W+)或者超过2G可以考虑分表。
    • 如何分表? 垂直拆分(将一个大表的字段拆分到多个表中);水平拆分(按照时间、用户ID、区域等水平拆分,拆分出的表都包含全部字段)。
    • 分表后非分表键的查询方案? ①将数据汇总到ES,进行ES查询;②遍历所有子表。
    • 分表可以考虑使用一致性hash算法(映射成一个hash环,顺时针寻找存储节点,可以增加虚拟节点平衡数据),扩展更方便。
    • 分库分表都要提前规划,根据业务需要存储的数据年份、数据量、数据增长情况,预估总数据量,衡量是否需要分库分表。评估后不需要拆分的尽量不拆分,会增加复杂度。
  • 分区表
    • 单个表中的数据按照某种规则划分成多个分区,这些分区逻辑上还属于同一个表,分区表可以提高查询性能,简化数据管理和维护。目前生产使用分区表,按月进行分区,每天数据18W左右(推荐单分区100W左右)。

八、MySQL索引

  • 索引: 一种特殊的数据结构,用于加快数据的查询速度。优点:①提高查询速度②唯一索引保证唯一;缺点:维护耗时,占用额外空间,增删改数据可能需要维护索引,性能降低。
  • 分类:
    • 逻辑维度:主键索引、唯一索引、普通索引、联合索引。
    • 物理存储维度:聚集索引、非聚集索引。
    • 数据结构维度:B+树索引、Hash索引、全文索引。
  • 索引的数据结构:
    • 为什么使用B+树结构?二叉树,可能产生数据偏移,极端情况下成为链表,效率低;平衡二叉树,每个父节点只有两个叶子节点,存储数据有限,树层级高,效率低;B树,多叶子节点存储数据,但每个节点都存储对应行的所有数据,相同存储空间存储的数据比B+树少,树的层级相对较高,效率低;B+树,多叶子节点,且每个节点存储键和对应数据的主键,相同空间存储的数据量大大增加,索引数据不满足查询要求时会进行会进行回表。
  • 索引失效:
    • or可能导致索引失效,解决:①使用union替换②优化查询语句,避免使用or。
    • 类型不匹配,索引失效。如库中为int,传入字符串。
    • like模糊匹配不符合最左原则,左侧存在通配符。
    • 索引列进行运算,或者使用函数,索引失效。
    • 联合索引,查询条件未满足左侧原则。例如联合索引(a,b,c),查询条件直接使用b或c等。
    • 使用is null 或者 is not null 可能导致索引失效。
    • 使用 != 或者 not in 可能导致索引失效。
    • 连表时,连表条件字段编码不一致,可能导致索引失效。
    • 经优化引擎优化后,预估全表扫描速度更快,则不使用索引。
  • 不适合建索引:
    • 数据量小。
    • 字段数据区分度不大,如性别。
    • 更新非常频繁的字段。
    • 没有作为查询条件、分组条件或排序条件的字段。
  • 索引下推: MySQL5.6之前,联合索引查询会每个条件都查询出主键ID,然后回表拿到数据再进行比对筛选,效率低下;MySQL5.6之后进行了优化,联合索引查询时满足前一个条件后不会进行回表,而是顺便向下判断后续条件是否满足,筛选完毕后再进行回表。
  • B+树索引和Hash索引比较:
    • B+树索引:支持范围查询;支持排序;支持模糊匹配;支持联合索引最左原则。
    • Hash索引:不支持范围查询;不支持排序;不支持模糊匹配;不支持联合索引;等值查询效率更高。
  • DDL操作(修改表结构/调整索引) 时,如果存在长事务、慢查询或死锁,DDL操作需要获取元数据锁,而且是写锁,会阻塞后续的所有操作,导致服务不可用。所以DDL操作时可能会影响正常业务,实际操作时有两种方案:①业务低峰期,且检查是否存在慢查询、死锁,存在则先kill掉;②建新表,数据迁移完成后切换到新表
  • 元数据锁: 用于保护数据库的元数据,如表结构、索引信息、事务状态的话,以保证正确性和一致性。
  • 想要进一步理解的小伙伴欢迎阅读另一篇文章《MySQL索引详解》

九、关键字书写顺序及执行顺序

  • 书写顺序:select distinct from join on where group by having union order by limit
  • 执行顺序:from on join where group by having select distinct union order by limit
  • select语句执行流程:连接->查询缓存->解析器->查询优化器->执行最优执行计划->返回结果并存入查询缓存。
  • 想要进一步理解的小伙伴欢迎阅读另一篇文章《MySQL关键字执行顺序》

十、explain

  • explain是MySQL 中常用的一个关键字,用于分析查询语句的执行计划,常用来进行SQL优化。
  • 原理: explain 模拟SQL执行流程,但并不会真正执行,最终返回SQL的执行计划。主要有以下几步:①将查询语句解析为一个语法树;②估算执行成本,并选出最优的执行计划,包括使用哪些索引、连接方式、排序方式、临时表等;③返回最优执行计划。

十一、MySQL主从同步流程

  • ① 主库开启binlog;
  • ② 从库连接主库,并发起同步请求;
  • ③ 主库将指定位置之后的数据打包发送给从库;
  • ④ 从库接收binlog并写入自己的中继日志(relaylog);
  • ⑤ 从库读取中继日志,应用到自己的数据上,完成同步。

十二、distinct与group by执行效率比较

  • distinct 和 group by 都会进行分组操作,在语意相同且有索引的情况下,两者效率相同;当语意相同但无索引的情况下,MySQL8.0之前group by 不进行隐式排序,效率低下,MySQL8.0之后删除了隐式排序,两者效率基本相同。

十三、Mybatis 源码执行流程

  • ① 获取配置文件流
  • ② 解析XML配置文件,构建SqlSessionFactory;
  • ③ 利用SqlSessionFactory创建SqlSession会话;
  • ④ 利用SqlSession创建Mapper接口的代理对象MapperProxy;
  • ⑤ 执行Mapper接口的SQL查询时,利用代理对象执行JDBC的SQL底层操作。

十四、分布式关系型数据库

  • OceanBase: 阿里巴巴集团自主研发的一款高性能、高可靠、高可扩展的分布式关系型数据库系统。它是一种基于分布式架构的数据库系统,旨在满足大规模数据存储和处理的需求,具有分布式、高可用、强一致性等特点。
  • PolarDB-X: 是阿里云推出的一款云原生分布式关系型数据库产品,是 PolarDB 系列产品的一部分。PolarDB-X 结合了传统数据库和云原生技术,旨在提供高性能、高可用性和弹性扩展的数据库解决方案。
相关推荐
Phoenixtree_DongZhao1 小时前
基于 Deep Flare Net 的可操作太阳耀斑预测模型
数据库·人工智能·空间科学
小洪爱分享1 小时前
Bug 解决 | 后端项目无法正常启动,或依赖服务连接失败
java·经验分享·redis·后端·mysql·bug·maven
半ོ糖ོ2 小时前
SQL报错注入之floor
数据库·sql
小白在路上~2 小时前
基于STC89C52单片机的U盘设计
数据库·单片机·mongodb
技术猿188702783512 小时前
数据库扩展新篇章:主流分库分表中间件全解析
数据库·中间件
d3126975102 小时前
在Nestjs使用mysql和typeorm
mysql·express·nestjs·typeorm
木小同3 小时前
redis面试(八)watchdog看门狗代码逻辑
数据库·redis·面试
一个热爱java的小白3 小时前
MySQL中常用工具
数据库·mysql
penguin_bark3 小时前
【Mysql】第七章 内置函数(日期函数+字符串函数+数学函数等)
数据库·sql·mysql
怀后同学.3 小时前
web安全-SQL注入的类型以及提交注入
数据库·sql·web安全