mysql存储引擎如何支持分区表_mysql分区优化与引擎设计

来源:这里教程网 时间:2026-02-28 20:47:14 作者:

MySQL 分区表只支持 InnoDB 和 MyISAM,但 MyISAM 已被弃用

MySQL 8.0 起,

CREATE TABLE ... PARTITION BY
语句仅允许在
InnoDB
存储引擎上创建分区表;
MyISAM
虽语法上仍接受分区定义,但实际不执行分区逻辑(写入全落一个分区),且官方已标记为废弃。使用
ARCHIVE
MEMORY
CSV
等引擎尝试建分区表会直接报错:
ERROR 1031 (HY000): Table storage engine for 't' doesn't support partitioning

实操建议:

新项目必须用
InnoDB
+ 分区,不要碰
MyISAM
分区
升级老系统前检查
SHOW CREATE TABLE t
是否含
ENGINE=MyISAM
PARTITION BY
,这类表需先转引擎再验证分区行为
InnoDB
分区本质是多个独立的
.ibd
文件(每个分区一个),不是逻辑切分,所以
innodb_file_per_table=ON
必须启用

分区键必须是主键/唯一键的全部组成部分

这是最常踩的坑:定义

PARTITION BY RANGE/LIST/HASH
时,分区表达式里涉及的列,必须包含在表的每个唯一约束(含主键)中。否则建表失败:
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

比如这张表会失败:

CREATE TABLE logs (
  id BIGINT PRIMARY KEY,
  dt DATE,
  msg TEXT
) ENGINE=InnoDB
PARTITION BY RANGE (YEAR(dt)) (
  PARTITION p2023 VALUES LESS THAN (2024),
  PARTITION p2024 VALUES LESS THAN (2025)
);

因为

id
是主键,但分区函数只用了
dt
,没包含
id
。修复方式只有两种:

dt
加进主键:
PRIMARY KEY (id, dt)
(注意顺序,
dt
放后面不影响查询效率)
改用
KEY(dt)
HASH(YEAR(dt))
,但前提是主键本身含
dt
或声明
UNIQUE KEY(dt)

没有“绕过”办法——这是 InnoDB 分区的硬性索引一致性要求。

分区裁剪失效的典型场景和验证方法

分区的价值全靠查询时的

partition pruning
(分区裁剪)。但很多看似能裁剪的 WHERE 条件,实际无法触发裁剪。常见失效点:

对分区字段用了函数:
WHERE YEAR(dt) = 2024
→ 不裁剪;必须写成
WHERE dt >= '2024-01-01' AND dt 
分区字段参与了计算:
WHERE dt + INTERVAL 1 DAY > '2024-01-01'
→ 不裁剪
使用了非确定性函数:
WHERE dt > NOW()
→ 优化器无法预判分区范围
JOIN 中分区表作为被驱动表,且 ON 条件未覆盖分区键 → 可能全分区扫描

验证是否裁剪:执行

EXPLAIN PARTITIONS SELECT ...
,看
partitions
列是否只列出目标分区(如
p2024
),而不是
p2023,p2024,p2025
NULL

分区数量不是越多越好,50 个以上要警惕

InnoDB 对单表分区数没有硬上限,但超多分区会显著拖慢 DDL 和查询优化阶段:

ALTER TABLE ... REORGANIZE PARTITION
会锁整个表,分区越多,元数据操作越慢
优化器估算执行计划时需遍历所有分区的统计信息,分区数 > 50 时
EXPLAIN
延迟明显上升
每个分区对应独立的
.ibd
文件,海量小分区易触发文件系统 inode 耗尽或 open file limit 问题
备份工具(如
mysqldump --tab
或物理备份)需逐个处理分区文件,恢复时间线性增长

真实建议:按月分区最多支撑 3–5 年历史数据(36–60 个分区);按天分区慎用,除非单日数据量稳定在 GB 级且查询极度聚焦最近 N 天;用

RANGE COLUMNS
替代多层嵌套函数,能减少分区管理复杂度。

分区不是银弹,它解决的是数据生命周期管理和大范围扫描的物理隔离问题,不是替代索引或分库分表的通用方案。真正卡住性能的,往往在分区之外。

相关推荐