This commit is contained in:
2026-05-24 11:42:38 +08:00
commit 30d312ac35
521 changed files with 146481 additions and 0 deletions
@@ -0,0 +1,221 @@
---
tags: [MySQL, MyISAM, Memory, Archive, 存储引擎]
create time: 2026-05-16 00:00
---
# MyISAM / Memory / Archive 引擎概览
## 概述
虽然生产环境几乎全部使用 InnoDB,但了解其他存储引擎的特点对于特定场景决策和理解 MySQL 历史演进仍然有价值。
## MyISAM
MyISAM 是 MySQL 4.x 时代的默认引擎,在 5.5 版本之后被 InnoDB 取代。
```mermaid
flowchart TB
subgraph FS["MyISAM 文件结构"]
MYD[".MYD — 数据文件"]
MYI[".MYI — 索引文件"]
FRM[".FRM — 表结构文件"]
end
subgraph FEAT["核心特性"]
T1["❌ 不支持事务"]
T2["❌ 不支持外键"]
T3["❌ 只有表锁<br/>无行锁"]
T4["✅ 压缩存储<br/>(myisampack)"]
T5["✅ 全文索引<br/>(8.0 前唯一选择)"]
T6["✅ 读密集型场景较快"]
end
style FS fill:#F8EFBA,color:#000
style FEAT fill:#D0E8FD,color:#000
```
> [!QUOTE] 思考一下
> MyISAM 将数据和索引分存为两个独立文件。这种设计看似简洁,但正是**缺乏事务支持(InnoDB 的 Redo Log + Undo Log)**和**行级锁**的根本原因——没有机制保证原子性和并发安全。
### MyISAM 的表锁机制
```mermaid
sequenceDiagram
participant C1 as Client A (WRITE)
participant S as Server
participant C2 as Client B (READ)
C1->>S: LOCK TABLES users WRITE
S->>S: 获取表级写锁
C1->>S: INSERT INTO users ...
C1->>S: UPDATE users SET ...
C1->>S: UNLOCK TABLES
C2->>S: SELECT * FROM users
Note over S: ⚠️ 阻塞!等待写锁释放
S-->>C2: (等待中...)
C1->>S: UNLOCK TABLES
S-->>C2: 返回结果集
```
> [!WARNING] 表锁的危害
> MyISAM 的表锁意味着**一个写操作会阻塞所有其他操作**(包括读)。在并发场景中这是灾难性的——即使是纯 SELECT 也会被阻塞。这就是为什么现代项目不应该再用 MyISAM。
### MyISAM 还能用在什么地方?
极少数场景:
- **静态只读日志**:导入一次、长期查询、绝不更新
- **GIS 数据**:MyISAM 的 spatial index 在某些老版本上更快
- **遗留迁移**:老旧系统的临时兼容层
> [!CAUTION] MyISAM 全文索引已过时
> MySQL 5.6+ 起 InnoDB 已支持 FULLTEXT 索引,8.0 后更是全面强化。MyISAM 作为"唯一全文索引选择"的优势已基本消失。
**结论:新项目不用 MyISAM。**
> [!TIP] 面试高频考点
> 面试官问"MyISAM vs InnoDB"时,核心差异就是三点:**锁粒度、事务、外键**。只要答出这三点,基本就拿满分了。
## Memory(HEAP)引擎
Memory 引擎将所有数据存储在内存中,表结构存在于磁盘 `.frm` 文件中。
```mermaid
flowchart TD
A["CREATE TABLE ... ENGINE=MEMORY"] --> B["数据全在内存"]
B --> C["极速读写 O(1)"]
B --> D["重启后数据丢失 ⚠️"]
C --> E["适合场景"]
E --> E1["临时聚合计算结果"]
E --> E2["字典表缓存"]
E --> E3["会话级临时查找表"]
style B fill:#EE5A24,color:#fff
style E3 fill:#00D866,color:#fff
```
```sql
-- Memory 引擎使用示例
CREATE TABLE session_lookup (
session_id CHAR(32) PRIMARY KEY,
user_id BIGINT,
last_access TIMESTAMP,
payload JSON
) ENGINE=Memory;
-- ⚠️ 注意限制
-- 1. VARCHAR/TEXT/BLOB 会使用 MEMORY 的内部映射转为固定长度
-- 2. 不支持 AUTO_INCREMENT
-- 3. 受 max_heap_table_size 和 tmp_table_size 限制
-- 4. 表在 MySQL 重启或 flush tables 时消失
-- 5. HASH 索引是默认值,BRIN 索引可通过 explicit index type 指定(MySQL 8.0+)
-- 💡 调优:调整上限
SET SESSION max_heap_table_size = 512 * 1024 * 1024; -- 512MB
SET GLOBAL tmp_table_size = 512 * 1024 * 1024;
```
> [!NOTE] Memory vs Redis
> 很多人问"能不能用 Memory 引擎代替 Redis 做缓存"。答案是:通常不建议。
> - Redis 有更丰富的数据结构(Sorted Set、Bitmap、Stream)
> - Redis 支持持久化和集群
> - Redis 有成熟的驱动和生态
> - MySQL Memory 引擎在连接断开时也会丢数据
## Archive 引擎
Archive 引擎专为"存而不查"的场景设计,采用行级锁 + 压缩存储。
```mermaid
flowchart LR
A["INSERT 数据"] --> B["Row-level compression<br/>每行独立压缩"]
B --> C["仅支持 SELECT / INSERT"]
C --> D["❌ 不支持 DELETE"]
C --> E["❌ 不支持 UPDATE"]
C --> F["❌ 不使用索引"]
style C fill:#FF9F43,color:#000
```
### 适用场景
| 场景 | 说明 |
|------|------|
| 日志归档 | 系统日志、审计日志只写不读 |
| 数据仓库 ETL | 海量事实表的增量导入 |
| 统计报表底表 | 定期导入后供离线分析 |
```sql
-- Archive 引擎示例
CREATE TABLE audit_log (
id BIGINT AUTO_INCREMENT, -- Archive 允许自增但不作索引查找用
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
action VARCHAR(50),
details TEXT,
PRIMARY KEY (id) -- 仅用于自增,不参与查找
) ENGINE=Archive;
-- ⚠️ MySQL 8.0+ 不再需要 ROW_FORMAT=COMPRESSED
-- Archive 引擎默认就是压缩存储,显式指定会报语法错误
-- 典型用法:按月分区归档
ALTER TABLE audit_log PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION p2026 VALUES LESS THAN (2027)
);
```
> [!NOTE] 为什么 Archive 不支持 UPDATE / DELETE?
> Archive 的行是**连续压缩存储**的——每一行都依赖于前一行解压后的位置。如果随机修改或删除中间某行,整个压缩链就要重新计算,这在设计上是不可接受的。所以它干脆禁止了这些操作,只保留 INSERT + SELECT。
## 引擎切换指南
### 如何查看当前支持的引擎?
```sql
SHOW ENGINES;
-- 关注 Support 列:YES(默认)、DEFAULT、NO(不支持)
```
### 如何修改引擎?
```sql
-- 创建新表时指定
CREATE TABLE archive_data (...) ENGINE=Archive;
-- 已存在表的转换(在线执行可能需要较长时间)
ALTER TABLE old_table ENGINE=InnoDB;
-- ⚠️ ALTER TABLE 原理
-- 1. 创建临时表(新引擎)
-- 2. 逐行拷贝旧表数据到新表
-- 3. 加排他锁,替换文件名
-- 4. 删除旧表
-- 大表转换会占用双倍空间和锁定时间
```
### 为什么生产环境几乎只用 InnoDB
```mermaid
flowchart TD
Check{"需要事务?"}
Check -->|是| INNODB["✅ InnoDB"]
Check -->|否| Q2{"高读低写?"}
Q2 -->|是| MEM{"✅ Memory(缓存)<br/>或 MyISAM(静态)"}
Q2 -->|否| ARCH{"纯追加场景?"}
ARCH -->|是| ARC["✅ Archive"]
ARCH -->|否| INNODB
style INNODB fill:#00D866,color:#fff
style MEM fill:#FF9F43,color:#000
style ARC fill:#C44569,color:#fff
```
> [!TIP] 决策原则
> 记住一句话:**"默认 InnoDB,特殊情况再考虑其他"**。InnoDB 是 MySQL 设计者的首选推荐,只有在性能极端优化或有特殊需求时,才值得切换引擎。
## 关联笔记
- [[hhs/MySQL/04-存储引擎/19-InnoDB 深度解析]] — InnoDB 五大核心组件完整文档
- [[hhs/GORM/13-多数据库支持]] — GORM 在不同数据库间的移植注意事项