myisampack只能用于MyISAM且必须停服务,因为它直接读写.MYD/.MYI文件、跳过SQL层与事务机制,要求表完全无写入以防文件损坏;InnoDB文件格式不兼容,运行会报错或静默失败。

MyISAM 表不能在线压缩,必须停写、用 myisampack 离线处理,且压缩后表变为只读 —— 这是硬限制,绕不开。
为什么 myisampack 只能用于 MyISAM 且必须停服务
myisampack 不操作 MySQL Server,而是直接读写 .MYD 和 .MYI 文件。它跳过 SQL 层,所以不依赖连接或事务,但因此要求表完全无写入(否则文件可能被并发修改导致损坏)。InnoDB 表有聚簇索引和 MVCC 机制,myisampack 完全不识别其文件格式,对 InnoDB 运行会报错或静默失败。
- 运行前必须确保没有
INSERT/UPDATE/DELETE操作,推荐先执行FLUSH TABLES WITH READ LOCK,再在 OS 层操作 - 压缩后的 .MYD 文件被重命名为
table_name.MYD→table_name.MYD(原名)+table_name.MYI被更新为指向压缩数据的索引结构 - 压缩不可逆:解压需用
myisamchk --unpack,不是简单改后缀
实际压缩流程与关键参数
假设数据库名为 testdb,表名为 logs,MySQL 数据目录为 /var/lib/mysql:
- 先退出 MySQL 或加全局读锁:
FLUSH TABLES testdb.logs WITH READ LOCK - 切换到数据目录:
cd /var/lib/mysql/testdb - 运行压缩:
myisampack -v logs(-v显示详细过程,含压缩率) - 重建索引(必须):
myisamchk -rq logs(-r表示修复,-q快速模式,跳过排序) - 解锁(如果用了
FLUSH):UNLOCK TABLES
注意:myisampack 默认不压缩索引文件(.MYI),只压缩数据文件(.MYD);若想进一步减小体积,可额外用 myisamchk --analyze --sort-index 优化索引顺序,但不会改变只读属性。
压缩后查询正常但写操作立刻报错
压缩完成并重启 mysqld 后,SELECT 没问题,但任何写操作都会触发错误:
ERROR 1036 (HY000): Table 'logs' is read only
这是预期行为,不是故障。MyISAM 压缩表在 MySQL 中被标记为 READ_ONLY,引擎层禁止写入。试图 INSERT 或 ALTER TABLE 都会失败。
- 无法通过
SET SESSION sql_log_bin = 0绕过 - 无法用
mysqldump --skip-triggers --no-create-info导出后再导入“解压”,因为 dump 出来的是 SQL,而压缩表的数据块格式已变,INSERT 会解析失败 - 唯一安全写入方式:先
myisamchk --unpack logs解包,再操作
性能与适用场景的真实权衡
压缩主要节省磁盘空间(通常 30%–70%,取决于字段重复度),但会带来 CPU 开销和轻微查询延迟 —— 每次 SELECT 需实时解压数据块。对于日志类只读归档表(如按月分表的 access_log_202301),收益明显;但对于高频点查的维度表(如 user_status),反而可能降低 QPS。
- 压缩后
SHOW TABLE STATUS中Data_length显著变小,但Index_length基本不变 -
myisampack不支持 Windows 下的长路径或 Unicode 表名,Linux 下也建议路径不含空格或特殊符号 - MySQL 5.7+ 仍保留该工具,但官方文档已标注为“deprecated”,未来版本可能移除 —— 新项目应优先考虑归档到列存(如 ClickHouse)或使用
ARCHIVE引擎
真正麻烦的不是怎么压,而是压完发现业务逻辑里混着 INSERT INTO ... ON DUPLICATE KEY UPDATE,而你忘了检查表是否只读。


















