bksczm头像
MySQL之存储引擎封面图

MySQL之存储引擎

一、存储引擎与"可插拔"架构

1.1 为什么说存储引擎是 MySQL 的核心

  • MySQL 架构中,SQL 层(连接管理、解析、优化、缓存)与存储层解耦;
  • 存储引擎决定了数据如何存储、如何索引、是否事务、如何加锁——同一张表的建表语法可以完全一样,但换引擎后行为天差地别;
  • 这就是"可插拔"(Pluggable)的含义:引擎以插件形式接入 MySQL 的存储层接口。

1.2 "可插拔" ≠ 运行时随便卸载

引擎类型是否能动态加载/卸载
内置引擎(InnoDB、MyISAM 等,编译进服务器)不能卸载,只能通过启动参数禁用(如 --skip-archive)
第三方插件引擎(MyRocks、TokuDB 等,编译成 .so)可通过 INSTALL PLUGIN / UNINSTALL PLUGIN 动态加载/卸载

所以准确说法是:MySQL 提供了插件式的引擎接口,第三方引擎可以动态挂载;但官方内置引擎是编译内建的。

1.3 SHOW ENGINES 输出解读

Support 列的含义:

取值含义
YES引擎已编译进服务器,且当前可用
DEFAULT已编译且是默认引擎(你的输出中 InnoDB 为 DEFAULT)
NO未编译进该发行版,不可用(官方二进制默认不含 FEDERATED,所以它是 NO)
DISABLED已编译,但被启动参数禁用(如 --skip-xxx)

加粗要点:NO 不是"配置文件里没开",而是"这个版本根本没编译它";Transactions: NULL 也表明引擎不可用。

1.4 常用查看命令

-- 查看默认引擎
SHOW VARIABLES LIKE 'default_storage_engine';
-- 查看某张表的引擎与行格式
SHOW TABLE STATUS LIKE 't1'\G
-- 查看支持的引擎
SHOW ENGINES;

二、InnoDB 存储引擎(默认引擎)

2.1 核心特性总表

特性维度InnoDB
默认引擎✅ MySQL 5.5 起为默认
事务✅ 支持(ACID,最大特点)
锁粒度行级锁(S 共享 / X 排他)
MVCC✅ 支持(undo log 实现)
索引类型B+Tree;聚簇索引(主键);8.0 支持全文索引、空间索引
HASH 索引❌ 不支持用户显式创建;✅ 内部有自适应哈希索引(AHI)
外键✅ 支持
崩溃恢复✅ redo + undo,自动恢复
主从复制✅ 基于 binlog
数据缓冲✅ Buffer Pool 统一缓存数据页 + 索引页
表压缩✅ 压缩行格式/页压缩,减少磁盘与内存占用
静态加密✅ 表空间加密
单表大小上限约 64TB(16KB 页)
备份支持mysqldump / XtraBackup / binlog 定点恢复(PITR)

2.2 逐项详解与答疑

2.2.1 聚簇索引

聚簇索引 = 索引与数据行存放在一起。主键索引的叶子节点直接存放整行数据;二级索引的叶子节点存放主键值(回表时再查主键索引)。所以:

  • 一张 InnoDB 表只有一个聚簇索引(主键);
  • 没建主键时,MySQL 选第一个非空唯一索引,再没有就用隐藏的 rowid。
2.2.2 表压缩:磁盘和内存都省
  • 磁盘:COMPRESSED 行格式 / 页压缩(8.0 支持 COMPRESSION 建表选项)显著减少磁盘占用;
  • 内存:压缩页在 Buffer Pool 中保持压缩状态,也间接减少内存占用。
2.2.3 数据缓冲:局部性 + 预读

Buffer Pool 依据局部性原理:访问某页时,把相邻页预读进内存,热点数据常驻内存,减少磁盘 IO。这就是 InnoDB 快的关键之一。

2.2.4 InnoDB 的"索引缓存"是什么?
引擎索引缓存数据缓存
InnoDB❌ 无独立索引缓存✅ Buffer Pool 统一缓存数据页+索引页
MyISAM✅ 独立 Key Cache(key_buffer_size)❌ 无数据缓存(靠 OS 文件缓存)

结论:InnoDB 没有单独的"索引缓存",数据页和索引页都放在 Buffer Pool 里统一管理;"索引缓存"(Key Cache)是 MyISAM 的专属特性。

2.2.5 行级锁

行锁分两种,语义完全不同:

锁类型缩写其他事务能否读其他事务能否写
共享锁S✅ 可读❌ 阻塞
排他锁X❌ 阻塞❌ 阻塞
  • 读操作加 S 锁,写操作加 X 锁;
  • 行锁基于索引记录实现(锁的是索引项,不是物理行);
  • 行锁并发高,但有死锁风险、加锁开销更大;表锁实现简单、无死锁,但并发低。生产 OLTP 首选 InnoDB 行锁。
2.2.6 答疑:不支持 HASH 索引,但"内部支持"是怎么回事?

两层含义:

  1. 用户层面:InnoDB 不允许你显式 USING HASH 建索引
  2. 内部层面:InnoDB 有自适应哈希索引(Adaptive Hash Index,AHI)——它自动在频繁等值访问的索引页上建立内存哈希索引,把 B+Tree 的多次 IO 降到 O(1) 查找。由 innodb_adaptive_hash_index 控制(默认开启)。

技巧:模拟哈希索引——对很长的列(如 url),额外加一列存哈希值(如 CRC32),对该列建普通索引,等值查询走哈希列索引,避免长列索引膨胀。

2.2.7 T 树索引是什么?

T-Tree(T 树)是内存数据库(Oracle TimesTen、早期 SAP HANA 等)使用的索引结构:

  • 一个节点存多个 key,减少内存指针开销;
  • 针对 CPU 缓存、内存访问优化;
  • InnoDB 是磁盘数据库,页大小对齐磁盘块(16KB),用 B+Tree 能把一次查询控制在少数几次磁盘 IO,所以不用 T-Tree。

一句话:T-Tree 属于内存数据库的索引方案,和 InnoDB 的 B+Tree 不是同一赛道。

2.2.8 update statistics for data dictionary

这不是一条日常 SQL 命令。优化器依赖统计信息(行数、列基数)选择执行计划,更新统计信息的标准方式是:

ANALYZE TABLE t1;
  • 8.0 中统计信息持久化存储在数据字典里(innodb_stats_persistent 默认 ON,采样页数 innodb_stats_persistent_sample_pages 默认 20);
  • 你看到的"update statistics for data dictionary"可理解为:InnoDB 支持维护数据字典相关的统计信息,属于内部机制,运维层面用 ANALYZE TABLE 即可。
2.2.9 MVCC 与主从复制
  • MVCC:靠 undo log + 版本链实现,读不阻塞写、写不阻塞读,是事务隔离的底层机制(详见事务篇);
  • 主从复制:通过 binlog 传递给从库。

2.3 物理文件

版本表结构数据 + 索引
5.7 及以前.frm 文件.ibd 文件
8.0数据字典集中存储(mysql.ibd,不再有 .frm).ibd 文件(innodb_file_per_table=ON 默认)

加粗要点:8.0 建表后,数据 + 索引在 .ibd,表结构在数据字典里


三、MyISAM 存储引擎

3.1 核心特性总表

特性维度MyISAM
默认引擎❌ 5.5 以前是默认,5.5 起让位 InnoDB
事务❌ 不支持
锁粒度表级锁
MVCC❌ 不支持
索引类型B+Tree、全文索引(FULLTEXT);❌ 无聚簇索引(数据与索引分离)
HASH 索引❌ 不支持
外键❌ 不支持
索引缓存✅ Key Cache(key_buffer_size),专门缓存索引块
数据缓存❌ 无(数据靠 OS 文件缓存)
崩溃恢复弱(崩溃后可能损坏,需 repair)
单表大小上限约 256TB(取决于文件系统)

3.2 物理文件

文件内容
.MYD数据文件
.MYI索引文件
表结构5.7 前是 .frm;8.0 起存数据字典(.sdi 是表空间描述,JSON)

加粗要点:MyISAM = 数据(.MYD)与索引(.MYI)分离存储,这正是它没有聚簇索引、二级索引叶子直接存行指针(而非主键)的原因。

3.3 三种存储格式

3.3.1 静态格式(Fixed)
  • 条件:表中不含可变长度列(VARCHAR/TEXT/BLOB 等)时自动使用,每行字节数固定;
  • 特点:最简单、最安全、最快;行位置可精确计算,天然支持随机访问;
  • NULL 列用 1 bit 额外空间记录是否为空。

答疑:VARCHAR 不是用多少给多少吗,为什么静态表要空格填充?

平时 InnoDB 里 VARCHAR 按实际长度存储,没错。但 MyISAM 静态格式为了保证"每行定长",会把 VARCHAR 也按声明最大宽度分配空间,尾部用空格填充(读取时一般会去掉)。这是 MyISAM 静态格式的历史设计——用空间换"行定长"带来的随机访问速度。BINARY/VARBINARY 则用 0x00 填充。

3.3.2 动态格式(Dynamic)
  • 条件:表含可变长度列(VARCHAR/TEXT/BLOB),或显式指定;
  • 特点:行长度可变,每行带长度标志;更新使行变长时,可能被移动到不连续空间,产生碎片;
  • 碎片整理:OPTIMIZE TABLE t1 或 myisamchk -r;
  • 每行前有 bitmap,标记哪些字符串列为空串/数字列为 0——值为 0/空串的列不占磁盘,节省空间;
  • 缺点:行分散 → 随机 IO 增多(你感觉"IO 次数很多"是对的),整体比静态格式慢。
3.3.3 压缩格式(Compressed)
  • 工具:myisampack 生成,只读表,内存占用极少,每行单独压缩、每列可选用不同压缩算法;
  • 解压/恢复:可用 myisamchk 处理(官方提示:压缩表只读,如需修改要先解压/重建)。

3.4 InnoDB vs MyISAM 一句话对比

对比项InnoDBMyISAM
事务/MVCC/外键/崩溃恢复✅❌
锁行锁(并发高)表锁(并发低)
聚簇索引✅❌
缓存Buffer Pool(数据+索引)仅 Key Cache(索引)
适用OLTP 读写混合只读/读多写极少、全文检索场景

四、MEMORY 存储引擎

4.1 核心特性总表

特性维度MEMORY
数据存储内存中(表结构在数据字典),重启丢失
索引✅ HASH 索引(默认),可指定 BTREE
事务❌
锁表级锁
持久化❌(仅结构定义保留)
大小上限受 max_heap_table_size 限制
适用临时数据、缓存、会话级中间结果

4.2 建表与释放

-- 用查询结果直接建内存表
CREATE TABLE tmp_mem ENGINE=MEMORY SELECT * FROM t1;

-- 释放内存
DELETE FROM tmp_mem;      -- 删除所有行,释放内存
TRUNCATE TABLE tmp_mem;   -- 整表清空,释放更快
DROP TABLE tmp_mem;       -- 彻底删除

注意:删除单行不会立即回收内存(碎片),只有 DELETE 全部行 / TRUNCATE / DROP 才整块释放。

4.3 三个问题

4.3.1 数据字典是什么?

数据字典(Data Dictionary)= MySQL 的元数据仓库:所有表结构、列、索引、权限、对象定义等集中存放。

  • 5.7 及以前:每张表一个 .frm 文件,分散管理;
  • 8.0:全部元数据集中存进 InnoDB 的 mysql.ibd(mysql 库),DDL 具备原子性(要么成功要么回滚,不再有"改一半"状态);
  • .sdi 文件:8.0 中伴随部分表空间出现的 JSON 格式表定义描述,用于部分场景(如 ibd2sdi 工具读取),不是日常运维对象。
4.3.2 和视图像吗?

本质不同:

维度MEMORY 表视图
数据真实物理存储(内存中)不存数据,查询时动态执行 SELECT
可写✅ 可增删改❌ 基本只读(可更新视图限制极多)
独立性独立数据依赖基表,基表变则结果变

视图是逻辑对象,内存表是物理数据。

4.3.3 被 Redis 替代了吗?

场景重叠,但没有完全替代:

  • Redis:独立进程、网络协议、丰富数据结构、可持久化——适合跨应用共享缓存;
  • MEMORY 表:MySQL 进程内,同一数据库会话/服务器内使用,事务内可见,SQL 直接操作;
  • 关键保留场景:MySQL 内部临时表(排序、分组、CREATE TEMP TABLE)大量使用内存表机制(8.0 起内部临时表默认用 TempTable 引擎,超出 temptable_max_ram 落盘)。

结论:对外缓存选 Redis;数据库内部临时存储用 MEMORY/TempTable,二者不冲突。


五、CSV 存储引擎

5.1 特性总表与文件

维度CSV
存储形式纯文本,逗号分隔(Comma-Separated Values)
索引❌ 不支持
事务/锁❌ 不支持事务;写时锁整表
NULL 支持❌ 不支持(见 5.2)
适用与其他系统交换数据(可直接用文本编辑器/Excel 打开)

建表后生成三个文件:

文件内容
.CSV数据(纯文本,逗号分隔)
.CSM表状态、元数据(行数、列信息)
.sdi表结构描述(JSON,8.0)

5.2 为什么"所有列都要求 NOT NULL"?

因为 CSV 是纯文本格式,无法表达 NULL 语义——空字段就是空字符串 '',与 NULL 无法区分。所以 CSV 引擎不支持 NULL 列(创建时建议显式 NOT NULL)。

5.3 注意点

  • 不支持索引、不支持 AUTO_INCREMENT、不支持分区;
  • 增删改会重写整个文件(IO 开销大),不适合高频写;
  • 典型用途:导入导出、与外部程序交换数据(如读 Excel 导出的 CSV)。

六、ARCHIVE 存储引擎

6.1 特性总表

维度ARCHIVE
用途归档存储:大量只写不查(或极少查)的历史数据
压缩✅ zlib 压缩,磁盘占用极小
操作主要支持 INSERT / SELECT;UPDATE/DELETE 受限或不可用(以当前版本官方文档为准)
索引支持极其有限(实践中基本无索引)
事务❌
适用日志归档、审计记录、历史明细

6.2 文件

文件内容
.ARZ压缩后的数据文件
.sdi表结构描述(JSON,8.0)
.ARNOPTIMIZE 优化期间可能出现的临时文件

注意:ARCHIVE 表数据只能追加,天然适合"写一次、存永久"的归档场景;不适合需要更新/删除的业务。


七、BLACKHOLE 存储引擎

7.1 特性

  • 接收一切写操作,但什么都不存;查询永远返回空结果;
  • 表结构定义正常存在,数据直接"丢进黑洞"。

7.2 用途

  1. 验证转储文件语法:把数据导入黑洞表,只验证 SQL 正确性;
  2. 测试二进制日志记录开销:对比开/关 binlog 的性能差异;
  3. 查找与存储引擎本身无关的性能瓶颈;
  4. 复制中间层:主库写 BLACKHOLE 表 + 开启 binlog → binlog 正常记录 → 从库收到并执行。可作为分发节点:多个从库共享一个写入入口,又不占主库磁盘。

八、MERGE(MRG_MYISAM)存储引擎

8.1 是什么

MERGE = 多个结构完全相同的 MyISAM 表的逻辑集合:

  • 对外像一张表,查询时并行扫描所有成员表再合并结果;
  • 建表方式:ENGINE=MRG_MYISAM UNION=(t1,t2)。

8.2 典型场景

  • 分表:把按月分出的 log_202501、log_202502… 合并成一张逻辑表查询;
  • 归档 + 查询:历史表只读归档,通过 MERGE 统一查询。

8.3 注意点

  • 成员表必须同为 MyISAM、结构完全一致;
  • 删除 MERGE 表不会删除成员表(成员独立存在);
  • 成员表缺一个/结构不一致都会导致 MERGE 表不可用;
  • 现代分表更推荐 InnoDB 分区表 或 ShardingSphere 等中间件,MERGE 已属历史方案。

九、FEDERATED 存储引擎

9.1 是什么

FEDERATED 允许本机表映射到远程 MySQL 服务器上的表:

  • 本地只存表结构定义,数据实际在远程;
  • 类似"跨库/分布式访问"的最小实现(MySQL 版 dblink)。

9.2 注意点

  • 官方发行版默认不编译(SHOW ENGINES 里 Support=NO),需要自行编译;
  • 性能差:每条查询都走远程网络往返,无法本地优化;
  • 安全/权限/网络稳定性问题多;
  • 生产慎用,跨库需求优先考虑应用层拆分或中间件。

十、EXAMPLE 存储引擎

  • 用途:存储引擎 API 的示例模板,给开发者演示"如何写一个存储引擎插件";
  • 特性:不真正存储任何数据(只有框架逻辑);
  • 不是给你生产用的,是给写引擎的人看的。

十一、全引擎横向对比与选择建议

11.1 横向对比大表

引擎事务锁索引外键MVCC持久化压缩典型场景
InnoDB✅行B+Tree/聚簇/全文/空间✅✅✅✅OLTP 生产默认
MyISAM❌表B+Tree/全文,无聚簇❌❌✅✅(工具)只读、全文检索
MEMORY❌表HASH/BTREE❌❌❌❌临时表/缓存
CSV❌表❌❌❌✅(文本)❌数据交换
ARCHIVE❌—极有限❌❌✅✅归档
BLACKHOLE❌—❌❌❌❌❌复制中间层/测试
MERGE❌表同 MyISAM❌❌✅—MyISAM 分表查询
FEDERATED跟随远程远程远程远程远程远程—跨库访问(慎用)
EXAMPLE———————引擎开发模板

11.2 选择建议(决策口诀)

业务场景推荐引擎
日常 OLTP(读写混合、要事务)InnoDB
只读报表、全文搜索MyISAM
会话级临时数据MEMORY
跨系统导入导出CSV
历史归档、只追加ARCHIVE
复制分发、性能测试BLACKHOLE

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/bksczm/article/details/169946651

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--