第1章 MySQL架构与历史

1. 概述

本章主要是讲解了MySQL的一个组织架构,包括存储引擎的一些关键设计和优缺点。对于MySQL的一个发展史也做了一个简单的介绍。

1.1 应用场景

  1. Web应用程序:网站、博客、论坛。提供了高性能读写,处理大量并发请求。
  2. 数据仓库:提供查询和数据分析工具,支持复杂查询和多表查询,用来生成分析报表。
  3. 嵌入式应用:作为一个嵌入式数据库引擎集成到应用程序中,数据存储本地文件系统。
  4. 游戏开发:存储用户数据、排行榜、用户数据、游戏日志等。
  5. 日志监控:高可扩展和持久性特征适合存储时间序列数据。

1.2 版本

1.2.1 MySQL 8.1.0 (2023-07-18)
具体更新参考
1.2.2 MySQL 8.0.34 (2023-07-18)
具体更新参考
1.2.3 MySQL 8.0.0 (2016-09-12)
8.0版本引入了许多新功能和改进,如全文搜索、JSON数据类型、窗口函数等,同时也增强了安全性和性能
1.2.4 MySQL 5.7.1 (2013-04-23)
5.7是目前最常用的版本,也是最稳定的版本。它在性能和安全性方面有很大改进,同时也支持JSON数据类型和多源复制等新功能
1.2.5 MySQL 5.6.2 (2011-04-11)
5.6是一个老版本,但仍然广泛使用。它在性能和安全性方面有一些改进,同时也支持一些新功能,如全文搜索和GIS支持
1.2.6 MySQL 5.5及以下版本
5.5及以下版本已经不再被官方支持,因此不建议使用。这些版本存在安全漏洞和性能问题,可能会导致数据丢失或泄漏。如果您仍在使用这些版本,请尽快升级到更高版本

2. MySQL架构

基础架构

在这里插入图片描述

1 连接层

本层提供的服务包括:连接处理、授权认证及安全处理等。

2 核心服务层

查询解析、分析、优化、缓存以及内置函数(日期、时间、数学和加密函数)存储过程,触发器,视图等功能也在这一层完成。

3 存储引擎层

通常叫做 Storage Engine Layer,也就是底层数据存取操作实现部分,由多种存储引擎共同组成。它们负责存储和获取所有存储在 MySQL 中的数据。就像 Linux 众多的文件系统 一样。每个存储引擎都有自己的优点和缺陷。服务器是通过存储引擎 API 来与它们交互的。这个接口隐藏了各个存储引擎不同的地方。对于查询层尽可能的透明。这个 API 包含了很多底层的操作。如开始一个事物,或者取出有特定主键的行。存储引擎不能解析SQL,互相之间也不能通信。仅仅是简单的响应服务器的请求。

4 数据存储层

主要是将数据存储在运行于裸设备的文件系统之上,存储引擎将数据的读写功能提交到数据存储层,由它来跟文件系统交互完成数据读写。

逻辑架构

MySQL服务器逻辑架构图

1. 核心服务层(SQL Layer)

核心模块由连接器、缓存、分析器、优化器、执行器等多个小模块构成,接下来介绍一些核心模块。
connectors:连接器
不同语言与MySQL的交互模块,如mysql-connector-php、mysql-connector-java等
connection Pool: 连接池
负责监听对 MySQL Server 的各种请求,接收连接请求,转发所有连接请求到线程管理模块。每一个连接上 MySQL Server 的客户端请求都会被分配(或创建)一个连接线程为其单独服务。而连接线程的主要工作就是负责 MySQL Server 与客户端的通信, 接受客户端的命令请求,传递 Server 端的结果信息等。线程管理模块则负责管理维护这些连接线程。包括线程的创建,线程的 cache 等。
SQL Interface: SQL接口
接收用户的命令,并返回用户需要查询的数据结果。
在 MySQL中我们习惯将所有 Client 端发送给 Server 端的命令都称为 query ,在 MySQL Server 里面,连接线程接收到客户端的一个 Query 后,会直接将该 query 传递给专门负责将各种 Query 进行分类然后转发给各个对应的处理模块。
Parser: 解析器
Query 请求经过 SQL接口层后就进入 SQL 解析器中,在解析器中 SQL 命令将会被验证和解析。解析器是由 Lex 和 YACC 实现的,是一个很长的脚本,主要功能是:

a. 将SQL语句进行语义和语法的分析,分解成数据结构,然后按照不同的操作类型进行分类,然后做出针对性的转发到后续步骤,以后SQL语句的传递和处理就是基于这个结构的。

b. 如果在分解构成中遇到错误,那么就说明这个sql语句是不合理的
Optimizer: 查询优化器
SQL 语句真正进入执行阶段之前,MySQL 会使用查询优化器对查询进行优化。根据客户端请求的 SQL 语句,和数据库中的一些统计信息,在一系列算法的基础上进行分析,从多种执行方案中找到一个最优的策略,并告诉后面的程序(数据库引擎)如何取得这个 SQL 语句的结果。优化器使用的是 “选取-投影-联接” 策略进行查询。
Cache&Buffer:查询缓存
Cache 主要的功能是将客户端提交给 MySQL 的 Select 类的 Query 请求的返回结果集缓存到内存中,并生成一个 Hash 数与该 Query 做对应。该 Query 所取数据的基表发生任何数据的变化之后, MySQL 会自动使该 query 的Cache 失效。在读写比例非常高的应用系统中, Query Cache 对性能的提高是非常显著的。当然它对内存的消耗也是非常大的。

如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key缓存,权限缓存等
Storage Engine: 存储引擎接口
存储引擎接口模块可以说是 MySQL 数据库中最有特色的一点了。目前各种数据库产品中,基本上只有 MySQL 可以实现其底层数据存储引擎的插件式管理。这个模块实际上只是一个抽象类,诸如 InnoDB, MyISAM 等都是这个抽象的具体实现。

经常出现的一个面试题:执行一条SQL语句会经历什么?

  1. 连接:客户端与服务端建立连接,会进行权限认证。
  2. 缓存:服务端先查询缓存,命中则返回,否则继续执行。
  3. 解析:SQL语法解析,并创建内部数据结构(解析树)
  4. 优化:各种优化比如:重写查询、表的读取顺序、选择合适的索引
  5. 执行:根据执行计划,调用存储引擎API进行查询。
  6. 结果:结果返回给客户端,同时存一份到缓存中。

2. 存储引擎层(Storage Engine Layer)

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式 。存储引擎是基于表的,而不是基于库的,所以存储引擎也可被称为表类型。我们可以在创建表的时候,来指定选择的存储引擎,如果没有指定将自动选择默认的存储引擎。mysql5.5之后默认的存储引擎是InnoDB。
show engines ; 用来查询当前数据库支持的存储引擎

  1. InnoDB
    支持事务,遵循ACID模型
    支持行级锁,提高并发访问性能
    支持外键FOREIGN KEY约束,保证数据的完整性和正确性
  2. MyISAM
    不支持事务,不支持外键
    支持表锁,不支持行锁
    访问速度快
  3. Memory
    内存存放,支持 hash索引
存储引擎区别
特点InnoDBMyISAMMemory
存储限制64TB
事务安全支持--
锁机制行锁表锁表锁
B+tree索引支持支持支持
Hash索引--支持
全文索引支持(5.6版本之后)支持-
空间使用N/A
内存使用中等
批量插入速度
支持外键支持--

面试题: InnoDB引擎与MyISAM引擎的区别 ?

  1. InnoDB支持事务、MyISAM不支持
  2. InnoDB支持行锁、MyISAM只支持表锁
  3. InnoDB支持外键、MyISAM不支持

3. 并发控制

并发控制主要是在多个对话并发访问数据库的时候,可能会带来脏数据、幻读等问题。所以MySQL提供了一些手段,来进行并发控制。该手段主要有表锁(锁住整张表)和行锁(锁住某些行)。

3.1 锁分类

1 表锁
表锁是MySQL中最基本的锁策略,并且是开销最小的策略。它会锁定整张表。
2 行锁
行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。InnoDB等比较常用的存储引擎中都实现了行级锁。
3 页级锁
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。
4 读锁(共享锁)
共享锁也称为读锁,它允许多个用户同时读取同一段数据,但不能修改数据。在MySQL中,可以使用SELECT语句来获取共享锁,例如:

SELECT * FROM table_name WHERE condition LOCK IN SHARE MODE;

该语句将对查询结果集中的每一行获取一个共享锁。其他用户可以同时获取相同的共享锁,但不能获取排他锁。
5 写锁(排他锁)
排他锁也称为写锁,它只允许一个用户访问数据,并且可以修改数据。在MySQL中,可以使用SELECT … FOR UPDATE语句来获取排他锁,例如:

SELECT * FROM table_name WHERE condition FOR UPDATE;

该语句将获取符合条件的行的排他锁。其他用户不能同时获取相同的排他锁,但可以获取共享锁。
6 间隙锁
使用范围条件匹配时,innodb会给符合条件的已有数据记录的索引加“范围锁”(范围锁是特殊的行锁),对于键值在条件范围内但并不存在的记录,叫做间隙(GAP),innodb也会对这个间隙加锁,这种机制叫做“间隙锁”。

3.2 优化技巧

  1. 尽可能使用共享锁:共享锁可以允许多个用户同时访问同一段数据,因此尽可能使用共享锁可以提高并发性能。
  2. 减少锁的持有时间:尽量缩短锁的持有时间可以减少锁的争用和等待时间,从而提高并发性能。
  3. 尽可能使用索引:使用索引可以减少数据扫描和锁的数量,从而提高并发性能。
  4. 使用合适的事务隔离级别:MySQL支持多种事务隔离级别,不同的隔离级别会对锁的使用和性能产生不同的影响,因此需要根据实际需求选择合适的隔离级别。

3.3 事务

事务就是一组 原子性的查询。简单说就是要么这组语句全部执行成功、要么这组语句全部执行失败。
事务的四个特性
原子性:一个事务是不可再分割的整体,要么都执行要么都不执行
一致性:一个事务的执行不能破坏数据库数据的完整性和一致性
隔离性:一个事务不受其它事务的干扰,多个事务是互相隔离的
持久性:一个事务一旦提交了,则永久的持久化到本地

3.4 隔离级别

READ UNCOMMITTED(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read(可重读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

面试题:什么是事务的ACID

  1. automicity 原子性
  2. consistency 一致性
  3. isolation 隔离性
  4. durability 持久性

4. 多版本并发控制

Multiversion Concurrency Control ,简称 MVCC 。
是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。

4.1 多版本并发控制解决了哪些问题

  1. 读写之间阻塞的问题
    通过 MVCC 可以让读写互相不阻塞,即读不阻塞写,写不阻塞读,这样就可以提升事务并发处理能力。
  • 提高并发的演进思路:
    • 普通锁,只能串行执行;
    • 读写锁,可以实现读读并发;
    • 数据多版本并发控制,可以实现读写并发。
  1. 降低了死锁的概率
    因为 InnoDB 的 MVCC 采用了乐观锁的方式,读取数据时并不需要加锁,对于写操作,也只锁定必要的行。

  2. 解决一致性读的问题
    一致性读也被称为 快照读
    ,当我们查询数据库在某个时间点的快照时,只能看到这个时间点之前事务提交更新的结果,而不能看到这个时间点之后事务提交的更新结果。

4.2 InnoDB工作原理

事务版本号
每开启一个事务,我们都会从数据库中获得一个事务 ID(也就是事务版本号),这个事务 ID 是自增长的,通过 ID 大小,我们就可以判断事务的时间顺序。

在 可重复读(REPEATABLE READ) 隔离级别下, InnoDB 的 MVCC 是如何工作的

  1. 查询(SELECT)
    InnoDB 会根据以下两个条件检查每行记录:
  • InnoDB只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以 确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的 。

  • 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保 事务读取到的行,在事务开始之前未被删除 。

    只有符合上述两个条件的记录,才能返回作为查询结果。

  1. 插入(INSERT)
    InnoDB为新插入的每一行保存当前系统版本号作为行版本号。
  2. 删除(DELETE)
    InnoDB为删除的每一行保存当前系统版本号作为行删除标识。
    删除在内部被视为更新,行中的一个特殊位会被设置为已删除。
  3. 更新(UPDATE)
    InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。

参考

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值