Skip to content

MariaDB 存储引擎:InnoDB、Aria、XtraDB、TokuDB

你需要在 MariaDB 中存储三类数据:

  • 用户订单(需要事务,高并发)—— 用什么引擎?
  • 日志数据(写入量大,不需要事务)—— 用什么引擎?
  • 历史报表(需要压缩,占用空间大)—— 用什么引擎?

MariaDB 支持 10+ 种存储引擎,每个引擎都有它的适用场景。选对引擎,性能可能提升 10 倍。


存储引擎概述

MariaDB 支持的存储引擎

┌─────────────────────────────────────────────────────────────┐
│                    MariaDB 存储引擎体系                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐     ┌─────────────┐                       │
│  │   InnoDB    │     │    Aria     │     ┌─────────────┐   │
│  │ (事务型)    │     │ (替代MyISAM)│     │   XtraDB    │   │
│  └─────────────┘     └─────────────┘     └─────────────┘   │
│                                                             │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐   │
│  │   TokuDB    │     │  CONNECT    │     │   Cassandra │   │
│  │ (写入密集型) │     │  (虚拟表)   │     │    (NoSQL)  │   │
│  └─────────────┘     └─────────────┘     └─────────────┘   │
│                                                             │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐   │
│  │   MyISAM    │     │   Memory    │     │  ColumnStore│   │
│  │ (兼容性)    │     │  (内存表)   │     │  (分析型)   │   │
│  └─────────────┘     └─────────────┘     └─────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

查看可用的存储引擎

sql
-- 查看所有存储引擎
SHOW ENGINES;

-- 查看当前默认引擎
SHOW VARIABLES LIKE 'default_storage_engine';

-- 查看表的引擎
SHOW TABLE STATUS FROM database_name;

-- 查看某个表的引擎
SHOW CREATE TABLE table_name;

InnoDB 存储引擎

概述

InnoDB 是 MariaDB(和 MySQL)的默认事务型存储引擎,提供 ACID 事务支持和行级锁。

MariaDB 的 InnoDB 实际上是 XtraDB 的延续,从 MariaDB 10.2 开始使用 Percona XtraDB 作为 InnoDB 的基础。

InnoDB 核心特性

特性说明
事务支持✅ ACID 完整支持
行级锁✅ 支持并发更新
外键约束✅ 支持
MVCC✅ 支持
自动崩溃恢复✅ 基于 redo log
聚簇索引✅ 主键索引
数据压缩✅ 支持

InnoDB 架构

┌─────────────────────────────────────────────────────────────┐
│                      InnoDB 架构                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────────────────────────────────────────────┐   │
│   │                  Buffer Pool                        │   │
│   │   ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐    │   │
│   │   │ Page 1 │ │ Page 2 │ │ Page 3 │ │ Page 4 │    │   │
│   │   └────────┘ └────────┘ └────────┘ └────────┘    │   │
│   └─────────────────────────────────────────────────────┘   │
│                         │                                   │
│         ┌───────────────┼───────────────┐                   │
│         ▼               ▼               ▼                   │
│   ┌──────────┐     ┌──────────┐     ┌──────────┐           │
│   │ Redo Log │     │Undo Log  │     │  System  │           │
│   │  (WAL)   │     │          │     │ Tablespace│          │
│   └──────────┘     └──────────┘     └──────────┘           │
│                                                             │
│   ┌─────────────────────────────────────────────────────┐   │
│   │               表空间 (.ibd 文件)                     │   │
│   │   数据页 ──► 索引页 ──► 插入缓冲 ──► 锁信息          │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Java 中使用 InnoDB

java
public class InnoDBDemo {
    
    public void createInnoDBTable(Connection conn) throws SQLException {
        // 显式指定 InnoDB 引擎
        String sql = """
            CREATE TABLE orders (
                id BIGINT PRIMARY KEY AUTO_INCREMENT,
                customer_id BIGINT NOT NULL,
                total_amount DECIMAL(10, 2) NOT NULL,
                status VARCHAR(20) DEFAULT 'pending',
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                INDEX idx_customer (customer_id),
                INDEX idx_status (status),
                INDEX idx_created (created_at)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
            """;
        
        try (Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
        }
        
        System.out.println("InnoDB 表创建成功");
    }
    
    // 事务示例
    public void transferMoney(Connection conn, long fromId, long toId, BigDecimal amount) 
            throws SQLException {
        
        conn.setAutoCommit(false);
        
        try {
            // 扣款
            String debitSql = "UPDATE accounts SET balance = balance - ? WHERE id = ?";
            try (PreparedStatement pstmt = conn.prepareStatement(debitSql)) {
                pstmt.setBigDecimal(1, amount);
                pstmt.setLong(2, fromId);
                if (pstmt.executeUpdate() == 0) {
                    throw new SQLException("账户不存在: " + fromId);
                }
            }
            
            // 收款
            String creditSql = "UPDATE accounts SET balance = balance + ? WHERE id = ?";
            try (PreparedStatement pstmt = conn.prepareStatement(creditSql)) {
                pstmt.setBigDecimal(1, amount);
                pstmt.setLong(2, toId);
                if (pstmt.executeUpdate() == 0) {
                    throw new SQLException("账户不存在: " + toId);
                }
            }
            
            conn.commit();
            System.out.println("转账成功");
            
        } catch (SQLException e) {
            conn.rollback();
            throw e;
        } finally {
            conn.setAutoCommit(true);
        }
    }
}

Aria 存储引擎

概述

Aria 是 MariaDB 开发的崩溃安全的 MyISAM 替代品,解决了 MyISAM 不支持崩溃安全的最大问题。

Aria vs MyISAM

特性MyISAMAria
崩溃安全
事务支持
表级锁
全文索引
压缩支持
内存使用中等
读性能

Aria 特有功能

sql
-- 创建 Aria 表
CREATE TABLE logs (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    level VARCHAR(20),
    message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=Aria;

-- Aria 表修复(崩溃恢复)
REPAIR TABLE logs QUICK;

-- Aria 转换为压缩格式
ALTER TABLE logs ENGINE=Aria ROW_FORMAT=COMPRESSED;

适用场景

  • 日志表:写入密集,不需要事务
  • 历史数据表:只读或很少修改
  • 临时表:不需要崩溃安全(可以用 MEMORY)
  • 只读缓存:需要快速读取
java
public class AriaDemo {
    
    public void createLogTable(Connection conn) throws SQLException {
        // 日志表适合使用 Aria
        String sql = """
            CREATE TABLE application_logs (
                id BIGINT AUTO_INCREMENT PRIMARY KEY,
                level VARCHAR(10) NOT NULL,
                logger VARCHAR(100),
                message TEXT,
                exception TEXT,
                thread_id INT,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                KEY idx_level (level),
                KEY idx_created (created_at)
            ) ENGINE=Aria 
            ROW_FORMAT=PAGE 
            DEFAULT CHARSET=utf8mb4
            """;
        
        try (Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
        }
    }
}

XtraDB 存储引擎

概述

XtraDB 是 Percona 开发的 InnoDB 的增强版,MariaDB 从 10.2 开始将 XtraDB 作为 InnoDB 的基础实现。

XtraDB 增强特性

特性标准 InnoDBXtraDB
页面压缩受限更好的支持
更改缓冲索引缓冲扩展的更改缓冲
压缩 InnoDB需要特殊编译内置支持
恢复性能中等更快
扩展性一般更好
监控接口基础增强

XtraDB 特有的系统变量

sql
-- XtraDB 特有的配置
SHOW VARIABLES LIKE 'innodb%';

-- XtraDB 页面压缩
SET GLOBAL innodb_compression_algorithm = 'lz4';

-- XtraDB 更改缓冲大小
SET GLOBAL innodb_change_buffering = 'all';

-- XtraDB 扩展缓冲池
SET GLOBAL innodb_buffer_pool_instances = 8;

使用场景

XtraDB 对应用透明——你不需要显式指定,MariaDB 默认就使用它:

java
// 这实际上使用的是 XtraDB
String sql = """
    CREATE TABLE user_sessions (
        session_id VARCHAR(64) PRIMARY KEY,
        user_id BIGINT,
        data JSON,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        expires_at TIMESTAMP,
        INDEX idx_user (user_id),
        INDEX idx_expires (expires_at)
    ) ENGINE=InnoDB
    """;
// MariaDB 内部使用 XtraDB 实现

TokuDB 存储引擎

概述

TokuDB 使用 Fractal Tree 索引,而非传统的 B-Tree,在写入密集型场景下性能显著优于 InnoDB。

Fractal Tree vs B-Tree

B-Tree (InnoDB):
        ┌───────┐
        │   50   │
       ┌┴───────┴┐
       ▼         ▼
    ┌─────┐   ┌─────┐
    │ 25  │   │ 75  │
    └─────┘   └─────┘
    
    写入:O(log n) 次 I/O(可能需要页分裂)
    读取:O(log n)

Fractal Tree (TokuDB):
        ┌───────┐
        │   50   │
       ┌┴───────┴┐
       ▼         ▼
    ┌─────┐   ┌─────┐
    │ 25  │   │ 75  │
    │[buf]│   │[buf]│  ← 每个节点有消息缓冲区
    └─────┘   └─────┘
    
    写入:消息在缓冲区异步合并,I/O 次数更少
    读取:O(log n)
    压缩:内置,压缩比高

TokuDB 特性

特性说明
Fractal Tree 索引写入优化
高压缩比通常 5-15x
事务支持
MVCC
索引覆盖
分区支持
在线 DDL

TokuDB 配置

sql
-- TokuDB 需要安装插件
INSTALL SONAME 'ha_tokudb';

-- 创建 TokuDB 表
CREATE TABLE big_data (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    event_time TIMESTAMP,
    metric_name VARCHAR(100),
    metric_value DOUBLE,
    tags JSON
) ENGINE=TokuDB
ROW_FORMAT=tokuzstd;  -- TokuDB 特有的压缩格式

-- TokuDB 特有的索引
CREATE INDEX idx_time ON big_data(event_time) USING tokudb;

适用场景

场景推荐引擎原因
高写入量日志TokuDBFractal Tree 优化写入
历史数据归档TokuDB高压缩比
交易数据InnoDB/XtraDB事务安全
只读报表Aria/ColumnStore读取优化
java
public class TokuDBDemo {
    
    public void createTimeSeriesTable(Connection conn) throws SQLException {
        // 时序数据适合 TokuDB
        String sql = """
            CREATE TABLE metrics (
                id BIGINT AUTO_INCREMENT,
                device_id VARCHAR(64) NOT NULL,
                timestamp DATETIME(3) NOT NULL,
                metric_name VARCHAR(100) NOT NULL,
                metric_value DOUBLE,
                PRIMARY KEY (id),
                UNIQUE KEY uk_device_time (device_id, timestamp, metric_name),
                KEY idx_timestamp (timestamp)
            ) ENGINE=TokuDB
            """;
        
        try (Statement stmt = conn.createStatement()) {
            stmt.execute(sql);
        }
        
        System.out.println("TokuDB 时序表创建成功");
    }
    
    // 批量写入性能测试
    public void benchmarkWrite(Connection conn, int count) throws SQLException {
        conn.setAutoCommit(false);
        
        String sql = "INSERT INTO metrics (device_id, timestamp, metric_name, metric_value) VALUES (?, ?, ?, ?)";
        long start = System.currentTimeMillis();
        
        try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
            for (int i = 0; i < count; i++) {
                pstmt.setString(1, "device_" + (i % 1000));
                pstmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
                pstmt.setString(3, "cpu_usage");
                pstmt.setDouble(4, Math.random() * 100);
                pstmt.addBatch();
                
                if (i % 1000 == 0) {
                    pstmt.executeBatch();
                }
            }
            pstmt.executeBatch();
            conn.commit();
        }
        
        long elapsed = System.currentTimeMillis() - start;
        System.out.printf("写入 %d 条数据,耗时 %d ms,速率 %d 条/秒%n", 
            count, elapsed, count * 1000 / elapsed);
    }
}

其他存储引擎

CONNECT 引擎

创建虚拟表,访问外部数据源:

sql
-- 安装 CONNECT 引擎
INSTALL SONAME 'ha_connect';

-- 创建 CSV 虚拟表
CREATE TABLE csv_data (
    id INT,
    name VARCHAR(100),
    value DOUBLE
) ENGINE=CONNECT TABLE_TYPE=CSV
FILE_NAME='/tmp/data.csv';

-- 创建 ODBC 虚拟表
CREATE TABLE remote_mysql SELECT * FROM odbc('dsn_name', 'SELECT * FROM users');

ColumnStore 引擎

列式存储,适合分析型查询:

sql
-- 创建 ColumnStore 表
CREATE TABLE analytics (
    date DATE,
    product_id INT,
    category VARCHAR(50),
    revenue DECIMAL(12,2),
    quantity INT
) ENGINE=ColumnStore;

MEMORY 引擎

内存表,极速访问:

sql
-- 创建内存表
CREATE TABLE session_cache (
    session_id VARCHAR(64) PRIMARY KEY,
    user_id BIGINT,
    data JSON,
    expires_at TIMESTAMP
) ENGINE=MEMORY;

-- 注意:服务器重启数据会丢失

存储引擎选择指南

选择决策树

需要事务支持吗?

    ┌───┴───┐
    │       │
   是       否
    │       │
    ▼       ▼
高并发写入?  需要崩溃安全?
    │       │
  ┌─┴─┐   ┌─┴─┐
  │   │   │   │
 是   否  是   否
  │   │   │   │
  ▼   ▼   ▼   ▼
TokuDB  InnoDB Aria  MyISAM

场景推荐

场景推荐引擎替代方案
普通业务表InnoDB-
高写入日志AriaTokuDB
时序数据TokuDBColumnStore
历史归档TokuDBAria
分析报表ColumnStoreInnoDB
缓存表MEMORYRedis
外部数据CONNECT-
只读配置Aria-

面试追问

追问一:InnoDB 和 MyISAM 的核心区别是什么?

维度InnoDBMyISAM
事务✅ 支持❌ 不支持
锁粒度行级锁表级锁
崩溃恢复自动需要手动修复
外键✅ 支持❌ 不支持
并发写入
全文索引✅ (更早支持)
索引缓存独立缓冲池键缓存

追问二:为什么 MariaDB 用 Aria 替代 MyISAM?

MyISAM 最大的问题是不支持崩溃安全——如果写入时数据库崩溃,数据可能损坏。

Aria 解决了这个问题:

  • 使用日志(WAL)保证崩溃安全
  • 事务性修复
  • 保持 MyISAM 的高性能

追问三:TokuDB 的 Fractal Tree 为什么写入更快?

传统 B-Tree 在写入时可能需要:

  1. 查找插入位置
  2. 如果页面满了,需要页分裂
  3. 可能触发级联分裂

Fractal Tree 使用消息缓冲区:

  1. 写入先进入缓冲区
  2. 缓冲区异步刷新到磁盘
  3. 大量随机写入可以合并成顺序写入

结果:写入 I/O 次数大幅减少


总结

引擎事务崩溃安全写入性能适用场景
InnoDB/XtraDB行级业务表(默认)
Aria表级日志、只读表
TokuDB行级极好时序数据、大数据
MyISAM表级临时/过渡表
MEMORY表级最快缓存
ColumnStore列级读优化分析报表

核心原则

  • 普通业务用 InnoDB(MariaDB 默认)
  • 写入密集型用 TokuDB
  • 只读/归档用 Aria
  • 分析型用 ColumnStore
  • 临时缓存用 MEMORY

下一步

基于 VitePress 构建