MyISAM 表空间是单文件还是多文件?
MyISAM 引擎把一张表拆成三个物理文件:
.frm(表结构)、
.MYD(数据)、
.MYI(索引)。没有统一的“表空间”概念,也不存在共享表空间一说。每个表独占一组文件,删表就是直接删这三个文件。
常见误区是以为
innodb_file_per_table=OFF时 MyISAM 也会进系统表空间——不会,它压根不走 InnoDB 那套逻辑。
.MYD文件默认用动态行格式,插入/删除频繁时容易产生碎片,
OPTIMIZE TABLE实际就是重建
.MYD+
.MYI如果磁盘上看到大量小
.MYD文件但
data_length很小,大概率是没做定期优化,碎片率已超 40% 迁移 MyISAM 表时必须三文件一起拷,只复制
.frm会导致 ERROR 1033 (HY000): Incorrect information in file: '
xxx.MYI'
InnoDB 的 ibdata1 和独立表空间怎么选?
关键看
innodb_file_per_table配置:ON 时每张表一个
.ibd文件;OFF 时所有表数据和索引都挤进共享表空间
ibdata1(可能还有
ibdata2等)。
生产环境几乎都该设为 ON。OFF 模式下最头疼的是:即使删掉几十 GB 的大表,
ibdata1文件体积也不会缩小,因为空间不会返还给文件系统。 从 OFF 切到 ON 不会自动迁移旧表,需逐个执行
ALTER TABLE t ENGINE=InnoDB
.ibd文件可直接用
cp或
xtrabackup --copy-back拷贝,但必须保证 MySQL 已执行
FLUSH TABLES t WITH READ LOCK或停机 误删
.ibd后仅剩
.frm,无法通过
CREATE TABLE LIKE恢复数据——InnoDB 元数据在
ibdata1里,没它就找不到数据页位置
如何查看某张表实际占用的磁盘空间?
别只看
information_schema.TABLES里的
data_length和
index_length,那只是引擎估算值。真实大小得看文件系统:
SELECT table_name, engine, round((data_length + index_length) / 1024 / 1024, 2) AS size_mb FROM information_schema.TABLES WHERE table_schema = 'db_name' AND table_name = 't';
然后对比磁盘上对应文件:
MyISAM:ls -lh /var/lib/mysql/db_name/t.MYDInnoDB(
innodb_file_per_table=ON):
ls -lh /var/lib/mysql/db_name/t.ibdInnoDB(
innodb_file_per_table=OFF):
ls -lh /var/lib/mysql/ibdata1—— 此时单表空间不可见
两者差异超过 10% 就说明有明显碎片或未刷新的脏页。
truncate table 为什么比 delete 快,又为什么不能回滚?
TRUNCATE TABLE是 DDL 操作,InnoDB 会直接释放整张表的数据页,重置
.ibd文件大小(或清空
ibdata1中对应段),不写 undo log,也不触发触发器。
而
DELETE FROM t是 DML,逐行标记删除、写 undo log、维护 MVCC 版本链——即使加了
WHERE 1=0,开销也远大于 truncate。 MyISAM 下
TRUNCATE实际等价于
DROP TABLE+
CREATE TABLE,会重建
.MYD和
.MYIInnoDB 下
TRUNCATE后自增 ID 重置为 1,但
DELETE不会 事务中执行
TRUNCATE会隐式提交当前事务,之后不能再
ROLLBACK—— 这点常被忽略,尤其在存储过程中混用时 InnoDB 表空间管理的核心其实是“段(segment)→ 区(extent)→ 页(page)”三级结构,但日常运维真正卡住人的,往往就是
ibdata1膨胀后无法收缩、
.ibd文件权限错乱导致启动失败、或者误以为
OPTIMIZE TABLE能回收
ibdata1空间。这些地方不翻源码也得摸清行为边界。
