MySQL介绍

作者:

在

image-20261016133620807

一、 DBA是什么?

DBA 是 Database Administrator 的缩写,中文叫 数据库管理员。

简单来说,DBA 就是企业里专门负责“照顾”数据库的人。如果把数据库比作一个巨大的仓库,DBA 既是仓库的建造者,也是保安,还是维修工和搬运工。他们的核心目标是保证数据库稳定、安全、高效地运行,确保数据不丢失、不泄露,且能被快速存取。

二. 二进制安装

当前运维和开发最常见的做法是二进制安装MySQL

  • 下载二进制包并且解压
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.6.40-linux-glibc2.12-x86_64.tar.gz
tar xzvf mysql-5.6.40-linux-glibc2.12-x86_64.tar.gz
  • 然后的步骤就和编译安装一样
mkdir /application
mv mysql-5.6.40-linux-glibc2.12-x86_64 /application/mysql-5.6.40
ln -s /application/mysql-5.6.40 /application/mysql #为了后续写的脚本,方便监控mysql
cd /application/mysql/support-files    #该文件夹有mysql初始化(预设)配置文件,覆盖文件是因为注释更全。
cp my-default.cnf /etc/my.cnf

mkdir /etc/init.d
cp mysql.server /etc/init.d/mysqld    # mysql.server包含如何启动mysql的脚本命令,让系统知道通过该命令启动mysql时的动作,该目录存放系统中各种服务的启动/停止脚本
cd /application/mysql/scripts
useradd mysql -s /sbin/nologin -M
 yum -y install autoconf    #不然会报错
./mysql_install_db --user=mysql --basedir=/application/mysql --data=/application/mysql/data
#  这个执行完后会出现   /application/mysql/bin/mysqld: error while loading shared libraries: libcrypt.so.1: cannot open shared object file: No such file or directory   错误

MySQL 启动时找不到名为 libcrypt.so.1 的系统依赖库。
安装缺失的库(推荐):
尝试安装 libxcrypt-compat 包,它提供了对旧版 libcrypt.so.1 的兼容支持。

yum install libxcrypt-compat

# 安装 Perl 核心模块包(包含 Sys::Hostname)
yum install -y perl-core


vim /etc/profile.d/mysql.sh    #写到环境变量的子配置文件内,未修改前只能使用/bin/mysql的命令才能启用,而不能全局使用
export PATH="/application/mysql/bin:$PATH"

source /etc/profile    #否则要重启系统才生效
  • ==需要注意,官方编译的二进制包默认是在/usr/local目录下的,我们需要修改配置文件==
sed -i 's#/usr/local#/application#g' /etc/init.d/mysqld /application/mysql/bin/mysqld_safe


修正脚本路径:使用 sed 把官方默认写死的 /usr/local 批量替换为你实际安装的 /application。

此时不可以通过systemctl命令启动,只能通过/etc/init.d/mysql start启动(Nginx也是,如果此时通过这样的命令启动Nginx,会导致systemctl start Nginx失败,因为冲突。)

  • 创建systemd管理文件,并且测试是否正常使用
  • 配置系统服务:编写 /usr/lib/systemd/system/mysqld.service 文件,以便用 systemctl 管理 MySQL。
vim /usr/lib/systemd/system/mysqld.service
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=https://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/application/mysql/bin/mysqld --defaults-file=/etc/my.cnf    #强制从my.cnf读配置,不然会从多个路径读配置
LimitNOFILE = 5000
server_id = 1    #用作主从的时候生效

## 这个配置文件里面的# 注释得删掉,出现中文,冲突了

vim /etc/my.cnf
 basedir = /application/mysql/
 datadir = /application/mysql/data

ln -s /usr/lib64/libncurses.so.6.2 /usr/lib64/libncurses.so.5
ln -s /usr/lib64/libtinfo.so.6.2 /usr/lib64/libtinfo.so.5

ls -l /usr/lib64/libncurses.so.5 /usr/lib64/libtinfo.so.5  #检验软链接是否建立成功
setenforce 0  # 这个很重要啊
systemctl daemon-reload
systemctl start mysqld
systemctl enable mysqld
chmod -R +x /application/mysql/bin/
# 此时ss -ntl 可以看到3306端口
ss -ntl

mysqladmin -uroot password '123456'
mysql -uroot -p123456
# 安装 EPEL 源
dnf install -y epel-release
# 再次尝试安装兼容库
dnf install -y ncurses-compat-libs

1. 运行身份不同(最核心的原因)

  • 你手动执行时: 你是用 root 身份敲下 /application/mysql/bin/mysqld ... 的。root 是 Linux 里的超级管理员,拥有最高权限,几乎不受任何限制,所以它可以畅通无阻地读取和执行任何文件。
  • 使用 systemctl 启动时: systemd 会去读取你的服务文件 mysqld.service,看到里面写了 User=mysql 和 Group=mysql。于是,systemd 会降权,让 mysql 这个普通用户去执行 /application/mysql/bin/mysqld。
  • 问题来了: 如果 /application 或 /application/mysql/bin/ 目录的权限设置得太严格(比如只允许 root 进入),普通的 mysql 用户连目录都进不去,更别提执行里面的文件了,所以系统直接报 Permission denied。

总结一下

  • 手动能启动:是因为你用 root 强行越过了权限和 SELinux 的限制。
  • systemctl 报错:是因为 systemd 严格按照 mysql 用户的权限和 SELinux 规则来办事。
  • 后来怎么成功的:因为你关闭了 SELinux,并且可能(如果没执行的话,建议执行一下)赋予了 /application 目录 755 权限,让 mysql 用户能够顺利访问并执行程序。

这也是为什么在生产环境中,老手通常会把 MySQL 装在默认路径(如 /usr/local/mysql)或者专门为它配置 SELinux 策略,就是为了避免这种让人头疼的权限问题。


MySQL体系结构管理

客户端与服务器模型

image-20261008160243758

1. 顶部示意图:C/S 架构与通信协议

  • 架构模式:图片最上方展示了 MySQL 是典型的 C/S(Client/Server,客户端/服务器) 结构。
    • 左侧方块是客户机进程(如 mysql 命令行工具),通过网络(TCP/IP)向服务器发送请求。
    • 右侧方块也是客户机进程(如 PHP 程序),通过应用程序接口(套接字)连接。
  • 通信协议:
    • 示意图中特别标出了 TCP/IP 和 mysql 协议,以及 PHP 和 套接字。这说明 MySQL 支持多种连接方式,底层的传输层可以是网络协议,也可以是本地套接字。

2. 核心知识点拆解

A.==MySQL 自带客户端程序==

文档指出 MySQL 安装后自带了一些位于 /application/mysql/bin 目录下的工具:

  • mysql:最常用的命令行客户端,用于交互式执行 SQL。
  • mysqladmin:用于执行管理操作(如关闭数据库、查看状态、修改密码等)。
  • mysqldump:用于数据库备份和导出数据的工具。

B. mysqld 守护进程(服务器端)

  • 定义:mysqld 是 MySQL 的二进制程序,也是后台运行的守护进程(Daemon)。它是数据库的核心,负责处理所有数据请求。
  • 运行模式:
    • 单进程:在操作系统层面看,它是一个单一进程。
    • 多线程:但在进程内部,它是多线程运行的。这意味着它可以同时处理多个用户的并发请求(每个连接通常会对应一个线程)。

C. 应用程序连接 MySQL 的方式

这是图片中最详细的部分,讲解了两种主要的连接方式:

方式一:TCP/IP 连接(远程连接)

  • 场景:当 PHP 应用和 MySQL 数据库不在同一台机器上时,必须使用 TCP/IP 方式。这也是最通用的远程连接方式。
  • 配置服务器(授权):
    • 为了让远程主机能连接,服务器端需要授权。
    • 命令:mysql> grant all privileges on *.* to root@'192.168.226.%' identified by '123456';
    • 解释:允许来自 192.168.226.x 网段的 root 用户,使用密码 123456 进行连接。
  • 配置客户端(安装与连接):
    • 安装:yum -y install mariadb(在 CentOS 等系统中,MariaDB 是 MySQL 的开源分支,通常作为客户端安装)。
    • 连接命令:mysql -uroot -p123456 -h192.168.226.X -P3306
      • -u:指定用户。
      • -p:指定密码。
      • -h:指定主机 IP(如果不加 -h,默认连本地)。
      • -P:指定端口(默认 3306)。

方式二:Socket 连接(本地连接)

  • 定义:这是 MySQL 的默认连接方式(当 -h 参数为空或指定为 localhost 时)。

  • 原理:它不经过 TCP/IP 协议栈,而是通过本地的 Unix Socket 文件(图片中路径为 /application/mysql/tmp/mysql.sock)进行通信。

  • 特点:

    • 快速:无需建立 TCP 三次握手,直接通过文件系统通信,速度比 TCP 更快。
    • 本地:仅限本机连接,无法跨网络。
  • 验证区别:

    • 图片底部有一行小字提示:mysql -uroot -p123456 -h127.0.0.1。注意这里用的是 IP地址 127.0.0.1,而不是 localhost。
    • 关键点:在 MySQL 中,使用 -h localhost 通常走 Socket 连接;而使用 -h 127.0.0.1 则强制走 TCP/IP 连接。这常用于排查网络配置问题。

总结

这张图主要为了讲清楚 MySQL 的两个核心概念:

  1. 服务器端 (mysqld):是一个多线程的后台进程,负责干活。
  2. 连接方式:分为远程的 TCP/IP 和本地的 Socket。本地开发用 Socket 快,生产环境跨机器用 TCP/IP,且需要进行权限授权。

image-20261008164445656

image-20261008164243222

3. 查找 Socket 文件

  • 命令:find / -name mysql.sock
  • 输出:
    • find: '/proc/30117': 没有那个文件或目录(这是一个无害的警告,通常是因为在 find 遍历过程中,某个进程刚好结束了,其 /proc 目录消失)。
    • /tmp/mysql.sock(这是关键结果!)
  • 原理:这对应了上面提到的“Socket,默认连接方式……通过 /application/mysql/tmp 下的 mysql.sock 文件”。在实际编译安装或配置中,这个 socket 文件的路径可能因配置文件(my.cnf)不同而有所变化。这里通过 find 命令确认了,当前服务器实际的 socket 文件位于 /tmp/mysql.sock。

方式一:显式指定 Socket 文件进行连接

  • 命令:mysql -uroot -p123456 -S /tmp/mysql.sock
  • 参数解析:==-S 参数用于显式指定 Socket 文件的路径==。
  • 结果:成功登录 MySQL!Your MySQL connection id is 8。
  • 意义:这证明只要客户端找到了正确的 socket 文件,即使不走网络协议,也能快速连上数据库。这是本地管理数据库最常用的方式之一。

方式二:通过 TCP/IP 强制本地回环连接

  • 命令:mysql -uroot -p123456 -h127.0.0.1
  • 参数解析:注意这里的 -h 指定了 127.0.0.1。
  • 结果:再次成功登录!Your MySQL connection id is 9(注意 ID 变成了 9,说明这是一次全新的独立连接)。
  • 原理与深度解析(极其重要):
    • 正如上面特别强调的:使用 -h localhost 通常走 Socket 连接;而使用 -h 127.0.0.1 则强制走 TCP/IP 连接。
    • 虽然是在本机,但 127.0.0.1 是一个 IP 地址。当客户端使用 -h 127.0.0.1 时,MySQL 客户端会将其视为网络请求,通过 TCP 协议封装数据包,经过操作系统的网络栈(回环接口 loopback),发往本机的 3306 端口。
    • 验证意义:这行命令验证了即使不通过外部网络,本机的 TCP/IP 网络栈、MySQL 对 3306 端口的监听以及权限配置都是完全正常的。

image-20261008170946811

Navicat 的作用和定义

Navicat 是一款非常著名的图形化数据库管理工具(GUI 客户端)。

之前的截图中,都是在 Linux 黑框框(命令行终端)里敲 SQL 语句,比如 grant all privileges...。这种方式虽然专业,但有几个缺点:

  1. 难记:需要记住复杂的 SQL 语法。
  2. 不直观:数据以文本形式展示,看几十条还行,看几万条就眼花。
  3. 易错:像您之前少打个分号 ; 就会报错。

Navicat 的作用就是解决这些问题:

  • 可视化操作:通过==鼠标点击==就能建库、建表、改数据、删数据,不需要手敲 SQL。
  • 数据表格化:像看 Excel 一样查看数据库里的数据(就像截图中右侧那样)。
  • 多数据库支持:它不仅能连 MySQL,还能连 MariaDB、Oracle、SQL Server、PostgreSQL 等。
  • 远程连接利器:就像截图左上角显示的 server1 连接,您可以在 ==Windows 电脑上通过 Navicat 轻松连接到虚拟机里的 Linux MySQL 数据库==,不再需要一直在黑框框里操作。

1. 表头字段(列)详解:

  • Host(主机):非常关键! 表示允许从哪台机器登录。
    • localhost:只允许本机(通过 Socket 或 127.0.0.1)登录。
    • 192.168.128.20:允许来自这个特定 IP 的远程机器登录。
    • 192.168.226.%:% 是通配符,表示允许 192.168.226.0 这个网段的所有机器登录。
  • User(用户):登录的用户名(如 root)。
  • Password(密码):这是加密后的密码。您看到的 *6BB4837EB7432Y... 这种乱码,是 MySQL 经过哈希算法加密后的密码(对应您命令行里输入的明文 123456)。
  • Select_priv, Insert_priv… 等(权限列):表示该用户有没有“查、增、改、删”的权限。Y 代表 Yes(有权限),N 代表 No(无权限)。
    • 看第一行 localhost / root,所有权限都是 Y,说明这是超级管理员。
    • 看第 6 行 localhost.localdomain / root,权限全是 N,这通常是系统自带的匿名或默认限制用户。
  • Grant_priv:表示该用户有没有“给其他人授权”的权限。
  • Shutdown_priv:表示该用户有没有“关闭数据库”的权限。

2.远程连接实验对应操作

  • 第 4 行:Host: 192.168.128.20, User: root。权限全是 Y。

    • 这就是在命令行里执行 grant all privileges on *.* to root@'192.168.128.20'... 的结果。==MySQL 把这条授权记录直接写进了这张 user 表里==。
  • 第 5 行:Host: 192.168.226.20, User: root。权限全是 Y。

    • 这也是授权的结果。所以您的客户端(IP 192.168.226.20)现在有权限连服务器了。

flush privileges刷新权限

当您在命令行敲 grant... 语句时,MySQL 其实是在后台修改这张 user 表。 为了保证性能,MySQL 在启动时会把这张表的内容加载到内存中。之后,用户登录验证都是读内存。 当您修改了这张表(无论是通过 SQL 语句,还是直接在这个 Navicat 界面里双击修改),内存里的数据和表里的数据就不一致了。 此时执行 flush privileges;,就是告诉 MySQL:“重新读取一下这张表,把最新数据加载到内存里,立刻生效!”

==总结==:Navicat 让您直观地看到了 MySQL 内部长什么样。您之前敲的代码(授什么权、给谁授权),最终的结果都以数据的形式存放在这张 mysql.user 表里。

在以后的实际工作中:

  • 写代码/搭建项目:用 Navicat 这类图形化工具。
  • 自动化脚本/服务器维护/应急排错:用命令行敲 SQL。两者结合使用效率最高

image-20261008194421985

image-20261008193813634

status语句看连接方式

image-20261008195128840

image-20261008201345874

第一视角:宏观映射(MySQL 逻辑 vs Linux 物理)

文档开篇的表格,是理解数据库最直观的切入点。==MySQL 作为一个运行在操作系统上的软件,它的逻辑概念最终都要落地为 Linux 的文件==。

MySQL 逻辑概念 Linux 物理概念 验证命令对比 核心含义
库 (Database) 目录 (Directory) show databases; vs ls -l / 建一个库,底层就是建一个文件夹。
表 (Table) 文件 (File) show tables; vs ls 建一张表,底层就是建一个或多个文件。
二维表 文件 无 元数据(表结构) + 真实数据行 = 文件名(表名) + 文件内容(数据)。

深度解析

当您在 MySQL 中执行 CREATE DATABASE school; 时,MySQL 会在它的数据目录(通常是 /var/lib/mysql/)下创建一个名为 school 的文件夹。当您执行 USE school; CREATE TABLE student(...) 时,MySQL 会在 school 文件夹下创建对应的物理文件(比如 .ibd 文件或 .frm 文件)。

第二视角:微观层级(InnoDB 存储引擎的物理结构)

这是文档最核心、最具技术含量的部分。它解释了当您敲下 CREATE TABLE 后,数据到底是如何在磁盘上安放的。

InnoDB 是 MySQL 默认的存储引擎,它遵循严格的“自上而下”的层级结构:

数据表 (逻辑对象) → 表空间 (物理容器) → 段 (Segment) → 区 (Extent) → 页 (Page)

我为您梳理这五个层级的关键知识点:

1. 数据表 与 表空间 (Tablespace)

  • 逻辑与物理的转换点:表是逻辑的,表空间是物理的(对应磁盘上的文件,如 .ibd 文件)。
  • 作用:表空间(Tablespace)是存储表数据(段、区、页)的物理容器,用于==存储数据表的所有数据(包括段、区、页)==
  • 类型:InnoDB 默认使用独立表空间(每张表一个 .ibd 文件,便于管理)或共享表空间(所有表共用 ibdata1)。

2. 表空间 与 段 (Segment)

表空间由多个段组成,段是 “同类型数据的集合”。

一个数据表至少包含 2 个核心段: 数据段(Data Segment):存储表中的实际数据行(对应 B + 树的叶子节点)。 索引段(Index Segment):存储表的索引数据(对应 B + 树的非叶子节点)。 若表有多个索引(如主键索引、二级索引),则每个索引会对应独立的索引段。 分区表中,每个分区会单独生成一套数据段和索引段,实现分区隔离。

  • 概念:表空间由多个“段”组成。段是“同类型数据”的集合。
  • 最重要的两个段:
    • 数据段:存您的真实数据行(比如用户的姓名、年龄)。
    • 索引段:存您的索引数据(比如主键索引的 B+ 树结构)。
  • 引申:如果您给表建了多个索引,就会有多个索引段。

3. 段 与 区 (Extent)

  • 概念:区是空间分配的基本单位。段申请空间时,不会一页一页地要,而是一次要一个“区”。
  • 固定大小:一个区默认固定为 1MB(包含 64 个 16KB 的页)。
  • 为什么要有区?:段扩展时,==会以 “区” 为单位向表空间申请空间==,避免频繁分配小单位导致的碎片。

4. 区 与 页 (Page)

  • 概念:页是 InnoDB 读写磁盘的最小 IO 单位。
  • 固定大小:默认 16KB。大小可配置(默认 16KB,可选 4KB、8KB、32KB、64KB),由innodb_page_size参数指定。
  • 核心运作机制(极其重要):
    • 即使您只想修改表里的一行数据(比如把名字“张三”改成“李四”),InnoDB 也不会只去读那一行,而是会把包含这一行的整个 16KB 的“页”从磁盘加载到内存中。
    • 修改完成后,再把整个页写回磁盘。这就解释了为什么数据库的内存(Buffer Pool)管理如此重要

第三视角:生动示例与总结

物理存储示例

以 user(id, name, age) 为例:

  1. CREATE TABLE user(...) 后:生成 user.ibd 文件(表空间),并自动生成 2 个段,==创建了数据段和索引段==。

  2. 插入第一行数据时:

  3. 数据段先申请 1 个区(1MB,含 64 个 16KB 页),将数据写入其中一个页。 索引段同步申请区和页,存储索引信息。

    • 数据段去申请 1 个区(1MB)。
    • 这 1MB 里有 64 个页(16KB/个)。
    • 数据被写入其中一个页里。
    • 索引段同理,申请区并存储 B+ 树节点的索引信息。
  4. 随着数据变多,一个区不够用了,段就会继续申请下一个区。

  5. 关键特点总结(帮助记忆)

    层级 作用 大小 / 特性
    数据表 逻辑对象,定义数据结构和关系 无固定大小,由数据量决定
    表空间 物理文件容器,存储表的所有数据 可动态增长(如 .ibd 文件)
    段 按数据类型分组(数据 / 索引) 由多个区组成,大小动态扩展
    区 段的分配单位,由连续页组成 固定 1MB(含 64 个 16KB 页)
    页 最小 IO 单位,存储实际数据或索引 固定大小(默认 16KB),是读写基本单位

InnoDB 引擎内部讲解

要理解这两个段,必须先知道 InnoDB 存储数据的核心数据结构:B+ 树。 在 InnoDB 中,一张表其实就是一棵或多棵 B+ 树。B+ 树由两部分组成:非叶子节点(负责指路) 和 叶子节点(负责存真实数据)。

“段(Segment)”是逻辑上的概念,它是同一种性质数据的集合。InnoDB 为了管理方便,把 B+ 树的“非叶子节点”和“叶子节点”分开存放,这就诞生了“索引段”和“数据段”。

一、 数据段(Data Segment)

1. 里面装的是什么?

  • 它专门用来存放 B+ 树的叶子节点。
  • 核心内容:表的真实数据行(比如 id=1, name='张三', age=18)。
  • 注意:如果您建表时设置了主键(InnoDB 强烈建议设置主键),那么数据段里的数据是按照主键顺序物理排序的。这就是所谓的“聚集索引”。

2. 它的物理特性:

  • 数据段在物理上是由多个区(Extent)组成的。
  • 当您插入第一行数据时,数据段会先申请 1 个区(默认 1MB,包含 64 个 16KB 的页)。数据被写入其中的某个页里。
  • 自动扩展:当这 1MB 写满了,数据段会自动去申请下一个区。这个扩展过程是 InnoDB 底层自动完成的,操作数据库的人完全无感知。

二、 索引段(Index Segment)

1. 里面装的是什么?

  • 它专门用来存放 B+ 树的非叶子节点(包括根节点和中间节点)。
  • 核心内容:它不存真实的整行数据,它只存“路标”。
  • 路标长什么样? 比如:1~100 页的数据,主键范围是 1 到 500;101~200 页的数据,主键范围是 501 到 1000。

2. 为什么需要独立的索引段?

  • 因为“目录(非叶子节点)”和“正文(叶子节点)”的更新频率和性质不同。目录通常很小,且相对稳定;正文很大,且频繁修改。把它们分成两个独立的“段”,物理隔离开,InnoDB 就能更高效地管理磁盘空间,避免频繁分配小空间导致的碎片。

3. 一个表有几个索引段?

  • 如果您只建了主键,那么主键这棵 B+ 树,就拥有 1 个数据段(存主键对应的真实数据) + 1 个索引段(存主键 B+ 树的目录)。
  • 如果您还给 name 字段建了二级索引,那么 name 也会生成一棵独立的 B+ 树。这棵 name 树也会有它自己的 1 个索引段(存 name 树的目录)和 1 个数据段(注意:这里的“数据段”存的不再是完整行数据,而是 name 和主键 id 的对应关系)。

三、 总结对照表

为了让您一目了然,我做一个极简的对比:

维度 数据段 (Data Segment) 索引段 (Index Segment)
在 B+ 树中的位置 叶子节点 (最底层的具体数据) 非叶子节点 (上面负责指路的节点)
存放的内容 真实的整行数据 (或二级索引+主键) 索引的目录、路标、范围指针
物理组成 由多个区(Extent)组成 由多个区(Extent)组成
扩展方式 写满一个区,自动申请下一个区 树变高变宽时,自动申请下一个区
对用户的可见性 完全不可见,底层自动管理 完全不可见,底层自动管理

==总结==

实际上,数据(叶子)和索引目录(非叶子)在物理磁盘上是分开存放在不同的段里的。它们是一棵树的两个部分,InnoDB 通过指针把它们连在一起。您查数据时,先走索引段(目录)找到指针,再顺藤摸瓜去数据段(正文)取数据。


流程图一:逻辑查询与 B+ 树结构(我们在用数据库时发生了什么)

这个流程展示了当我们执行一条 SQL 去查询数据时,InnoDB 是如何通过索引段指路,最终在数据段拿到数据的。

graph TD
    A["客户端发起查询 (SELECT * FROM user WHERE id=18)"] --> B("进入 InnoDB 存储引擎")
    B --> C{"查找主键 B+ 树"}

    C -->|第一步 走索引段| D["索引段 (Index Segment)"]
    D --> D1["非叶子节点 (根节点)"]
    D1 --> D2["非叶子节点 (中间节点)"]
    D2 -.->|记录着路标 找到目标页的指针| E("找到目标页的指针")

    E -->|第二步 走数据段| F["数据段 (Data Segment)"]
    F --> F1["叶子节点 (Page 页)"]
    F1 --> F2["取出真实的整行数据 (id=18, name=张三)"]

    F2 --> G["返回给客户端"]

    style D fill:#f9f,stroke:#333,stroke-width:2px
    style F fill:#bbf,stroke:#333,stroke-width:2px

图解核心:

  • 索引段(粉色):只负责“指路”,告诉你数据在第几个页。它本身不包含“张三”这个具体名字。
  • 数据段(蓝色):负责“存货”,最终的真实数据(id=18, name=张三)都在这里。
  • 它们是 B+ 树上同一棵树的两个不同部分,物理上是分开放的。

流程图二:物理存储层级(InnoDB 在磁盘上是怎么建房子的)

这个流程展示了从建表到插入数据,底层物理空间是如何一步步分配的(对应文档里的“表 → 表空间 → 段 → 区 → 页”)。

graph TD
    %% 第一阶段:创建表空间
    Start["执行 CREATE TABLE user"] --> Space["创建独立表空间 user.ibd 文件"]

    %% 第二阶段:划分段(左右分流)
    Space --> Seg1["划分出 数据段"]
    Space --> Seg2["划分出 索引段"]

    style Seg1 fill:#bbf,stroke:#333,stroke-width:2px
    style Seg2 fill:#f9f,stroke:#333,stroke-width:2px

    %% 第三阶段:段申请区(左右并行)
    Seg1 -->|插入第一行数据时| Ext1["申请 1 个区 Extent"]
    Seg2 -->|同步创建索引时| Ext2["申请 1 个区 Extent"]

    style Ext1 fill:#fff3cd,stroke:#ffc107,stroke-width:1px
    style Ext2 fill:#fff3cd,stroke:#ffc107,stroke-width:1px

    %% 第四阶段:区划分为页(独立分组)
    subgraph 区与页的物理构成
        direction TB
        Ext1 -->|固定 1MB| P1["包含 64 个页 Page"]
        Ext2 -->|固定 1MB| P2["包含 64 个页 Page"]
        P1 -->|每个页固定 16KB| DataBlock["存入真实的行数据"]
        P2 -->|每个页固定 16KB| IndexBlock["存入路标 目录"]
    end

    %% 第五阶段:数据写满后的自动扩展循环
    DataBlock --> Check{"数据写满了吗"}
    Check -->|没满| UseEmpty["继续使用区里空闲的页"]
    Check -->|满了| AutoExt["段自动申请下一个区 1MB"]
    AutoExt -.->|循环扩展| Ext1

    %% 为分组框设置颜色
    style 区与页的物理构成 fill:#f5f5f5,stroke:#ccc,stroke-width:1px

图解核心:

  1. 建表时,底层会自动分好“地盘”(段)。
  2. 段不是直接要“页”,而是要“区”。因为一次要 1MB(64个页)比一次要 16KB 效率高得多,不容易产生磁盘碎片。
  3. 自动扩展:当 1MB 的区被 64 个页填满后,段会自动去申请下一个区。这个动作完全由 InnoDB 在底层默默完成。