
一、 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体系结构管理
客户端与服务器模型

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 的两个核心概念:
- 服务器端 (
mysqld):是一个多线程的后台进程,负责干活。 - 连接方式:分为远程的 TCP/IP 和本地的 Socket。本地开发用 Socket 快,生产环境跨机器用 TCP/IP,且需要进行权限授权。


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 端口的监听以及权限配置都是完全正常的。
- 正如上面特别强调的:使用

Navicat 的作用和定义
Navicat 是一款非常著名的图形化数据库管理工具(GUI 客户端)。
之前的截图中,都是在 Linux 黑框框(命令行终端)里敲 SQL 语句,比如 grant all privileges...。这种方式虽然专业,但有几个缺点:
- 难记:需要记住复杂的 SQL 语法。
- 不直观:数据以文本形式展示,看几十条还行,看几万条就眼花。
- 易错:像您之前少打个分号
;就会报错。
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。两者结合使用效率最高


status语句看连接方式


第一视角:宏观映射(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) 为例:
-
CREATE TABLE user(...)后:生成user.ibd文件(表空间),并自动生成 2 个段,==创建了数据段和索引段==。 -
插入第一行数据时:
-
数据段先申请 1 个区(1MB,含 64 个 16KB 页),将数据写入其中一个页。 索引段同步申请区和页,存储索引信息。
- 数据段去申请 1 个区(1MB)。
- 这 1MB 里有 64 个页(16KB/个)。
- 数据被写入其中一个页里。
- 索引段同理,申请区并存储 B+ 树节点的索引信息。
-
随着数据变多,一个区不够用了,段就会继续申请下一个区。
-
关键特点总结(帮助记忆)
层级 作用 大小 / 特性 数据表 逻辑对象,定义数据结构和关系 无固定大小,由数据量决定 表空间 物理文件容器,存储表的所有数据 可动态增长(如 .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
图解核心:
- 建表时,底层会自动分好“地盘”(段)。
- 段不是直接要“页”,而是要“区”。因为一次要 1MB(64个页)比一次要 16KB 效率高得多,不容易产生磁盘碎片。
- 自动扩展:当 1MB 的区被 64 个页填满后,段会自动去申请下一个区。这个动作完全由 InnoDB 在底层默默完成。