必须停库或确保表完全无写入才能执行myisampack,因其非在线操作,直接读写.MYD文件,否则会导致数据错位、索引偏移或文件截断;官方警告--skip-external-locking启用时并发操作将引发不可恢复损坏。

必须停库或确保表完全无写入,再执行 myisampack,否则压缩后表损坏或无法加载——这不是可选步骤,是硬性前提。
为什么压缩前必须停写?
MyISAM 表压缩不是在线操作:myisampack 直接读写 .MYD 文件,若 mysqld 正在写入,会导致数据错位、索引偏移甚至文件截断。官方明确警告:如果 mysqld 启用了 --skip-external-locking(默认开启),myisampack 和服务器并发操作会引发不可恢复的损坏。
- 最稳妥方式:停掉
mysqld,再运行myisampack - 次选方式:确保该表已
FLUSH TABLES WITH READ LOCK,且无任何活跃事务或连接在访问它 - 别信
--wait选项——它只等“表文件没被其他进程打开”,不等 MySQL 内部缓存刷盘完成
压缩命令与关键参数怎么配?
命令目标必须是 .MYI 文件(或省略后缀的表名),路径要完整;压缩后 .MYD 变小,.MYI 会极小(常只剩 1KB),但结构仍需保留。
- 基础命令:
myisampack /var/lib/mysql/dbname/tablename.MYI - 加
-b自动备份原始.MYD为tablename.MYD.OLD,防误操作 - 加
-f强制覆盖残留的.TMD中间文件(常见于上次中断) - 别用
--join合并表——归档场景要保留单表粒度,且合并后无.frm文件,易出错
执行后你会看到类似 Compressing tablename.MYD: (1248932 records) - 58.32% 的输出,末尾一定有提示:Remember to run myisamchk -rq on compressed table。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
压缩后表打不开?漏了这步就白干
压缩只改 .MYD,但索引文件 .MYI 里的指针还指向旧偏移量,不重建索引 = 表不可读。报错通常是 ERROR 1036 (HY000): Table 'xxx' is read only 或直接 Table doesn't exist。
- 必须立刻执行:
myisamchk -rq /var/lib/mysql/dbname/tablename.MYI - 加
--sort-index可优化后续查询性能(尤其范围扫描) - 加
--analyze更新统计信息,避免优化器误判行数 - 执行完后,要么重启
mysqld,要么在 MySQL 内执行FLUSH TABLES,否则服务仍读旧缓存
权限和只读状态怎么真正锁死?
SET GLOBAL read_only = ON 对 MyISAM 完全无效;压缩表虽引擎层只读,但文件系统权限没锁住,mysql 用户仍能删/覆盖 .MYD。
- MySQL 层加固:
SET GLOBAL innodb_read_only = 1(MySQL 8.0+),它禁用所有引擎的 DDL,防止新建同名表覆盖 - 文件系统加固:
chmod 444 /var/lib/mysql/dbname/tablename.MYD,彻底移除写权限(注意:不能设 400,否则 mysql 用户自己也读不了) - 两者缺一不可:前者拦 SQL,后者拦直接文件操作;单独做任一个都有绕过风险
最后检查是否生效:用普通账号连上库,执行 INSERT INTO tablename VALUES (...),应立刻报 ERROR 1036 (HY000): Table 'tablename' is read only;同时尝试 echo test > tablename.MYD 应提示 Permission denied。










