myisam仅支持range/list/hash分区且不支持key分区,分区键须为整数表达式并属主键/唯一索引;innodb支持全部四种分区类型,允许date/datetime列直接函数分区,但禁止外键且跨分区操作易引发锁竞争与死锁。

MySQL分区分表时,MyISAM和InnoDB的限制差异不是“性能快慢问题”,而是“能不能合法分区”和“分区后是否还能用”的根本区别。
MyISAM不支持所有分区类型,且部分分区会失效
MyISAM只支持RANGE、LIST、HASH三种分区类型,完全不支持KEY分区(哪怕你用主键字段也不行)。更关键的是:即使语法上能建成功,某些场景下分区实际不生效——比如对TEXT或BLOB列做RANGE分区时,MySQL 5.7+ 会静默降级为未分区表,SHOW CREATE TABLE里还显示有PARTITION BY,但SELECT * FROM information_schema.PARTITIONS查不到分区信息。
- MyISAM分区必须基于整数表达式,不能直接用
TO_DAYS(created_at)这类函数,得提前转成UNIX_TIMESTAMP()再取模 - 分区键必须是主键/唯一索引的组成部分,否则
CREATE TABLE直接报错ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function -
ALTER TABLE ... REORGANIZE PARTITION在MyISAM中不可用,只能DROP+RECREATE,期间表完全不可写
InnoDB分区支持更全,但事务与锁行为会变化
InnoDB支持全部四种分区类型(RANGE/LIST/HASH/KEY),也允许对DATE、DATETIME列直接使用TO_DAYS()或YEAR()函数。但要注意:分区不改变引擎本质,INSERT仍走事务,UPDATE仍可能触发行锁升级为意向锁甚至表锁——尤其当WHERE条件无法定位到具体分区时。
- 跨分区
UPDATE或DELETE(例如WHERE status IN (1,2) AND created_at > '2025-01-01'命中多个分区)会同时持有多个分区的锁,死锁概率比单分区高 -
SELECT COUNT(*)在InnoDB分区表上不会像MyISAM那样读元数据,而是真实扫描每个分区的聚簇索引,性能反而更差 - 分区表上的外键约束被完全禁止:
ERROR 1505 (HY000): Partitioned tables do not support foreign keys,连REFERENCES关键字都会被拒绝
分区维护操作在两者间行为不一致
最常踩的坑是TRUNCATE PARTITION和EXCHANGE PARTITION——MyISAM执行TRUNCATE PARTITION p1是立即释放磁盘空间且不可回滚;InnoDB执行同样语句却是先标记删除再异步清理,期间ibdata1文件大小不变,且该操作属于DDL,会阻塞其他DML。
-
EXCHANGE PARTITION要求交换表必须是InnoDB引擎且结构完全一致(包括ROW_FORMAT、KEY_BLOCK_SIZE),MyISAM表无法参与交换 - MyISAM分区表执行
OPTIMIZE TABLE会逐个重建每个.MYD/.MYI文件,而InnoDB的OPTIMIZE TABLE本质是ALTER TABLE ... FORCE,会重建整个表空间,耗时长、锁表久 - 备份时,
mysqldump --single-transaction对InnoDB分区表有效,但对MyISAM分区表无效(无事务),必须加--lock-all-tables
真正麻烦的不是选哪个引擎来分区,而是分区本身会让MyISAM失去仅存的优势(如COUNT(*)元数据读取),又无法获得InnoDB的事务保障;而InnoDB分区则放大了锁竞争和运维复杂度。多数情况下,与其强行分区,不如先确认是否真需要——比如日志类数据,用TIME_TO_SEC(NOW()) % 100做分表路由,比硬上分区更可控。











