mysql存储引擎如何实现数据表空间管理_mysql数据存储解析

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

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.MYD
InnoDB(
innodb_file_per_table=ON
):
ls -lh /var/lib/mysql/db_name/t.ibd
InnoDB(
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
.MYI
InnoDB 下
TRUNCATE
后自增 ID 重置为 1,但
DELETE
不会
事务中执行
TRUNCATE
会隐式提交当前事务,之后不能再
ROLLBACK
—— 这点常被忽略,尤其在存储过程中混用时
InnoDB 表空间管理的核心其实是“段(segment)→ 区(extent)→ 页(page)”三级结构,但日常运维真正卡住人的,往往就是
ibdata1
膨胀后无法收缩、
.ibd
文件权限错乱导致启动失败、或者误以为
OPTIMIZE TABLE
能回收
ibdata1
空间。这些地方不翻源码也得摸清行为边界。

相关推荐