前言
前段时间看了《MySQL是怎样运行的》这本书,书中介绍了MySQL数据结构,从数据结构角度去谈MySQL的特性。写这篇博客是做个总结,以下内容需要读者对MySQL有基础的认识和掌握,同时对于数据结构有一定的了解。所以这边先会对,数据结构和二分法,做些基本的介绍。然后再讲MySQL数据,是通过哪种数据结构存储的。如果掌握了其中的数据结构,那么当中的原理就掌握了。一些特性,索引,优化。就自然而然的理解了。变得非常简单。
套用《道德经》里的话就是道
技术分为两种,具体的做事方法是术,做事的原理和原则是道。
二分法
因为后面要介绍的MySQL数据结构,很多地方要用到二分法,这边单独拿出来讲一遍。
小时候,玩过的猜数字游戏
1-100范围内随机选择一个数,猜这个数字是多少。如果你猜的数比目标大,它会告诉你大了;比目标小,它会告诉你小了;等于目标告诉你答对了。如何在最少次数获得答案
那时候,我们就知道猜数字。要对半猜,这样猜的速度最快。以上如果方法,学名就叫做二分法。
我们看下官方介绍:
二分法的基本思想是,将数组或列表分成两部分,判断目标元素在哪一部分中,然后继续在该部分中进行查找,直到找到目标元素或确定目标元素不存在为止。
二分法适用于有序数组或有序列表中,时间复杂度O(log n)
public static int search(int[] a, int target) {
int lo = 0;
int hi = a.length - 1;
while (lo <= hi) {
System.out.println(String.format("lo=%s,hi=%s", lo, hi));
int mid = lo + (hi - lo) / 2;
if (a[mid] > target) {
hi = mid - 1;
} else if (a[mid] < target) {
lo = mid + 1;
} else {
return mid;
}
}
return -1;
}
以上是最基础的,还有两种变形:owerBound(下界)和upperBound(上界)
// Lower Bound(下界): Lower Bound 是指在已排序数组中,比目标值大的第一个元素的位置索引。也可以说是第一个大于等于目标值的元素的位置索引。
// 如果数组中存在多个相同目标值,则返回最左边的位置
public static int lowerBound(int[] a, int target) {
int lo = 0;
int hi = a.length;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] < target) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
}
// Upper Bound(上界): Upper Bound 是指在已排序数组中,比目标值大的第一个元素的位置索引。也可以说是第一个大于目标值的元素的位置索引。
// 如果数组中存在多个相同目标值,则返回最左边的大于目标值的位置。
public static int upperBound(int[] a, int target) {
int lo = 0;
int hi = a.length;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] <= target) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
}
以上变体思想,再接下来会使用到,大家可以先品味一下。如果不是很理解,那么可以将代码执行下。
数据结构 | 优点 | 缺点 | 特性 | 访问时间复杂度 | 插入时间复杂度 |
---|---|---|---|---|---|
数组 | - 快速随机访问 | - 固定大小,不灵活 | - 连续存储 | O(1) | O(n) |
链表 | - 动态大小 | - 随机访问慢 | - 灵活插入、删除 | O(n) | O(1) |
栈 | - 后进先出 | - 仅允许在栈顶插入和删除 | - 递归、表达式求值 | O(1) | O(1) |
队列 | - 先进先出 | - 随机访问慢 | - 广度优先搜索、任务调度 | O(n) | O(1) |
树 | - 分层结构 | - 平衡维护复杂 | - 二叉树、二叉搜索树 | O(log n) | O(log n) |
堆 | - 高效的插入、删除 | - 不支持随机访问 | - 最大堆、最小堆 | O(log n) | O(log n) |
哈希表(散列表) | - 快速的插入、删除、查找 | - 内存消耗相对较大 | - 高效的散列函数、冲突处理 | O(1) | O(1) |
二叉搜索树(Binary Search Tree) | - 查找、插入和删除操作的时间复杂度为O(log n) | - 会退化成O(n) | - 左子树中的所有节点都小于根节点,右子树中的所有节点都大于根节点 | O(m) | O(m) |
红黑树(Red-Black Tree) | - 自平衡,保持搜索效率 | - 相对复杂的实现 | - 高效的搜索、插入、删除 | O(log n) | O(log n) |
B树(B-Tree) | - 高度平均性能,适用于大数据集 | - 不适用于小数据集 | - 多叉搜索树 | O(log n) | O(log n) |
B+树(B+ Tree) | - 顺序访问性能好 | - 节点拆分和合并操作相对复杂 | - 子节点形成了一个有序链表 | O(log n) | O(log n) |
B树和B+树,大家可能会比较陌生,接下来的内容又比较重要。这边做个简单介绍。
特性 | B树 | B+树 |
---|---|---|
结构 | 所有节点都存储数据和关键字 | 非叶子节点只存储关键字,叶子节点存储数据 |
查找效率 | 略低,因为非叶子节点不包含全部关键字 | 高,由于非叶子节点不包含全部关键字 |
范围查询 | 低效,需要在非叶子节点和叶子节点之间遍历 | 高效,叶子节点形成有序链表,支持范围查询 |
插入和删除操作 | 相对复杂,可能导致树的失衡 | 相对稳定,树的平衡性较好 |
节点利用率 | 低,因为非叶子节点存储关键字和数据 | 高,由于非叶子节点只存储关键字 |
适用场景 | 适用于内存和外存储 | 主要用于外存储,如数据库索引、文件系统 |
节点拆分和合并操作 | 相对频繁 | 相对较少 |
删除记录时性能 | 略高 | 略低 |
数据检索和迭代效率 | 相对低效 | 高效,有序链表可支持顺序遍历 |
图片来源于网络
对于B树和B+树介绍,可以参考平衡二叉树、B树、B+树、B*树 理解其中一种你就都明白了这篇博文
MySQL简介
MySQL客户端请求服务器的过程:
连接管理:
建立连接: 客户端通过TCP/IP协议与MySQL服务器建立连接。连接过程中,客户端和服务器协商通信协议版本、认证方式等信息。
握手阶段: 服务器发送握手数据包,包含服务器版本、连接ID等信息。客户端接收握手数据包并回应,选择认证方式。
认证阶段:
身份验证: 客户端发送身份验证信息,通常是用户名和密码等。服务器验证信息的合法性,如果认证通过,客户端获得访问权限。
查询缓存:
查询缓存检查: 服务器在接收到客户端的查询请求后,会检查查询缓存,看是否已经缓存了相同的查询。如果在缓存中找到了相同的查询,服务器直接返回缓存结果,而不执行实际查询。
语法解析:
解析SQL语句: 服务器对客户端发送的SQL语句进行语法解析,确保语法正确。如果语法错误,服务器返回错误信息。
查询优化:
查询优化器: 服务器使用查询优化器分析查询语句,确定最佳执行计划。这涉及索引的选择、连接顺序等优化步骤。
存储引擎:
执行计划: 优化后的查询计划交给存储引擎层执行。存储引擎负责管理表、索引,并执行具体的读取、写入操作。
结果返回:
结果传输: 存储引擎返回执行结果给服务器,服务器将结果传递给客户端。结果可以是查询结果集、执行状态信息等。
断开连接:
关闭连接: 当客户端不再需要与服务器通信时,可以选择主动断开连接。客户端发送断开连接请求,服务器关闭连接。如果是持久连接,可以选择保持连接以便后续的请求。
存储引擎是数据库管理系统(DBMS)中的一个关键组件,负责管理数据的存储、检索和索引等操作。存储引擎定义了数据库系统如何组织、存储和操作数据,决定了数据库的性能、事务支持、并发控制和其他关键特性。
常见的MySQL存储引擎:
InnoDB: InnoDB是MySQL的默认存储引擎,提供了ACID事务支持、行级锁、外键约束等特性。支持事务、行级锁、外键,适合并发,**数据存储方式是按照主键顺序存储**
MyISAM: MyISAM是MySQL的另一个常见的存储引擎,它不支持事务和行级锁,但具有较高的性能和较小的存储开销。MyISAM适用于读密集型应用,如数据仓库和日志分析。按照插入顺序存储;
MEMORY: MEMORY存储引擎将表数据存储在内存中,提供了非常快速的数据访问速度,但在数据库关闭时数据会丢失。适用于小型临时表或缓存数据。相当于Redis
NDB Cluster: NDB Cluster存储引擎是MySQL Cluster的一部分,提供高可用性和分布式数据库功能,适用于需要水平扩展的分布式应用。
CSV: CSV存储引擎以纯文本形式存储数据,适用于数据交换或导出。
Archive: Archive存储引擎专注于高度压缩的数据存储,适用于大量历史数据的存储。
在上面的存储引擎用的比较多是InnoDB和MyISAM,大家重点记得InnoDB数据存储方式是按照主键顺序存储,MyISAM按照插入顺序存储。以下内容介绍的都是InnoDB存储引擎
InnoDB记录结构
行格式
InnoDB 存储引擎支持不同的行格式,每种行格式有其自身的优势和适用场景。在 InnoDB 存储引擎中,常见的行格式包括 COMPACT、REDUNDANT、DYNAMIC(默认) 和 COMPRESSED。
行格式就是我们存储的每一条记录,一条记录就是一行。那么这条记录长什么样。
行格式 | 描述 | 适用场景 |
---|---|---|
COMPACT | 默认的行格式,压缩存储数据,提高性能和空间效率。 | 适用于不包含太多变长列的表。 |
REDUNDANT | 旧版行格式,包含冗余信息,已不再推荐使用。 | 主要用于向后兼容。 |
DYNAMIC | 对变长列进行动态存储,适用于包含大量变长列的表。 | 适用于具有许多变长列的表。 |
COMPRESSED | 压缩行格式,通过 zlib 压缩算法减小存储空间。 | 适用于 I/O 受限的环境,提高性能。 |
COMPACT 格式
这边介绍的是COMPACT 格式,COMPACT 和DYNAMIC相差不多。