MyISAM单表大小受MAX_ROWS和AVG_ROW_LENGTH建表时预设值影响,而非运行时配置;InnoDB无原生单表大小限制,但受表空间与文件系统约束;.ibd文件删除数据不缩容,需ALTER TABLE重建释放空间。

MyISAM单表文件大小受MAX_ROWS和AVG_ROW_LENGTH实际约束
MyISAM 表物理上对应三个文件(.MYD、.MYI、.frm),其中数据文件 .MYD 的最大尺寸默认是 4GB(32 位文件偏移限制),但可通过建表参数突破——关键不是“改配置”,而是建表时显式指定 MAX_ROWS 和 AVG_ROW_LENGTH,让 MySQL 预分配足够大的文件头信息。
常见错误现象:ERROR 1114 (HY000): The table 't' is full,即使磁盘还有空间,也可能是 MyISAM 自身的行数/大小预估溢出导致拒绝写入。
-
MAX_ROWS不是硬上限,而是提示 MySQL “预计最多存多少行”,影响初始.MYD文件扩展策略和索引节点大小 -
AVG_ROW_LENGTH必须配合MAX_ROWS使用,否则 MySQL 可能忽略MAX_ROWS;估算值宁大勿小(比如实际平均 200 字节,设为 512) - 32 位系统下,即使设了大值,
.MYD文件仍可能卡在 4GB —— 这是 OS 层限制,需用mysqld --large-pages或迁移到 64 位环境 - 运行中无法通过
ALTER TABLE ... MAX_ROWS=...动态提升限制,必须DROP + CREATE
InnoDB 没有单表物理大小限制,但受innodb_data_file_path配置与文件系统影响
InnoDB 表数据逻辑上统一管理在表空间(tablespace)中,不按表拆分文件(除非启用 innodb_file_per_table=ON)。所谓“单表大小限制”,其实是间接的:要么是共享表空间撑满,要么是独立 .ibd 文件触及文件系统单文件上限(如 ext4 默认支持 16TB,xfs 支持更大)。
容易被忽略的一点:即使开了 innodb_file_per_table,新建表也不会自动限制大小;InnoDB 本身不提供类似 MAX_ROWS 的 DDL 约束机制。
- 检查当前表空间是否快满:
SELECT FILE_NAME, TABLESPACE_NAME, ENGINE, TOTAL_EXTENTS*64 AS size_kb FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE='DATAFILE'; - 若用共享表空间(
ibdata1),扩容需停库、修改innodb_data_file_path并指定autoextend,例如:ibdata1:12M:autoextend:max:512M - 启用
innodb_file_per_table后,每个表的.ibd文件可单独OPTIMIZE TABLE回收空闲页,但不会自动收缩 —— 删除数据后文件大小不变,需ALTER TABLE t ENGINE=InnoDB触发重建 - MySQL 5.7+ 支持
innodb_page_size=64K(编译时指定),可略微提升大表扫描效率,但会增加内存占用,且不可逆
真正可控的“单表大小限制”只能靠应用层或触发器模拟
MySQL 原生不支持 MAX_FILESIZE 或 LIMIT DATA SIZE 这类语法。想硬性阻止某张表超过 10GB,不能依赖存储引擎参数,得换思路。
典型做法是监控 + 干预:用定时任务查 information_schema.tables,结合 data_length + index_length 判断大小,超限时写入日志、发告警,甚至执行 INSERT ... SELECT 归档或 RENAME TABLE 切表。
- 获取某表近似大小(单位字节):
SELECT data_length + index_length FROM information_schema.tables WHERE table_schema='db' AND table_name='t'; - 触发器方案不可行:无法在
BEFORE INSERT中可靠读取当前表总大小(涉及 MVCC 和统计信息延迟) - 分区表(
PARTITION BY RANGE)可间接控制单个分区大小,但需提前规划分区键和边界,且ALTER TABLE ... REORGANIZE PARTITION开销大 - 最稳妥的边界控制是在应用写入前做预估:比如每条记录约 1KB,目标上限 5GB → 最多插 500 万行,由业务代码计数拦截
innodb_file_per_table开启后,.ibd文件增长不可逆,删除数据不释放磁盘空间
这是线上最容易误判的点:看到 DELETE FROM t WHERE ... 执行成功,df -h 却发现磁盘没腾出空间,ls -lh t.ibd 文件大小纹丝不动。
原因在于 InnoDB 的页管理机制 —— 删除只是把页标记为空闲,供后续 INSERT 复用,不会返还给文件系统。
- 唯一释放
.ibd文件空间的方法是重建表:ALTER TABLE t ENGINE=InnoDB(MySQL 5.6+ 支持 online DDL,但仍需额外磁盘空间暂存新文件) -
OPTIMIZE TABLE t在innodb_file_per_table=ON下等价于上述ALTER TABLE ... ENGINE=InnoDB,但会锁表(除非使用ALGORITHM=INPLACE且满足条件) - 如果磁盘已满,无法执行重建,只能先
mysqldump导出有效数据,DROP表,再导入 —— 这是最暴力但也最确定的方式 - Percona Toolkit 的
pt-online-schema-change可规避长锁,但要求主从延迟低、binlog_format=ROW,且同样需要双倍磁盘空间
.ibd 文件膨胀后首次 ALTER TABLE 的不可控耗时。


















