mysql 5.6.6+ 的 innodb 表默认启用独立表空间(innodb_file_per_table=on),但需通过 show variables like 'innodb_file_per_table' 确认值为 on 才支持;若为 off,则仅新创建或重建的表可使用独立表空间,且 alter table ... tablespace 要求目标表空间已存在、表为 innodb 类型、非系统表/临时表,并会触发全表重建加锁。

确认表是否支持独立表空间
MySQL 5.6.6+ 的 InnoDB 表默认使用共享表空间(ibdata1),要启用独立表空间,必须开启 innodb_file_per_table。如果该配置关闭,ALTER TABLE ... TABLESPACE 会直接报错 ERROR 1031 (HY000): Table storage engine for 't' doesn't have this option。
检查方式:
SHOW VARIABLES LIKE 'innodb_file_per_table';返回
ON 才能继续。若为 OFF,需先在 my.cnf 中设置并重启 MySQL,但注意:已有表不会自动迁移,仅影响后续新建或重建的表。
使用 ALTER TABLE ... TABLESPACE 移动已有表
只要表是 InnoDB 类型、且 innodb_file_per_table=ON,就可以用 ALTER TABLE 指定表空间名。注意:目标表空间必须已存在,MySQL 不会自动创建。
操作步骤:
- 先创建表空间(如名为
ts_user):CREATE TABLESPACE ts_user ADD DATAFILE 'ts_user.ibd' ENGINE=InnoDB;
- 再移动表:
ALTER TABLE users TABLESPACE ts_user;
- 验证是否生效:
SELECT NAME, SPACE, FILE_FORMAT, ROW_FORMAT FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE '%users%';
结果中SPACE值应与INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES中ts_user对应的SPACEID 一致
⚠️ 重要限制:该操作会重建整张表(类似 ALGORITHM=COPY),期间加排他锁,大表会阻塞写入;不支持分区表整体迁移,需逐个子分区处理。
常见失败原因和对应修复
执行 ALTER TABLE ... TABLESPACE 报错时,大概率不是语法问题,而是底层状态不满足:
-
ERROR 1814 (HY000): Tablespace has been discarded:目标表空间被手动执行过DISCARD TABLESPACE,需先IMPORT TABLESPACE或重建 -
ERROR 1932 (42S02): Table doesn't exist in engine:表在磁盘上缺失.ibd文件(比如误删),或表处于损坏状态,SHOW CREATE TABLE都可能失败 -
ERROR 1030 (HY000): Got error 194 from storage engine:通常是磁盘空间不足,或ibd文件所在目录权限不对(MySQL 进程需有读写权限) - 对临时表、系统表(如
mysql.*)、或使用ROW_FORMAT=COMPRESSED且未启用innodb_file_format=Barracuda的表,操作会被拒绝
移动后要注意文件归属和备份逻辑
表移动到独立表空间后,物理文件(如 ts_user.ibd)不再位于 datadir 下的数据库子目录中,而是放在 datadir 根目录或指定路径(取决于 CREATE TABLESPACE 时的路径)。这意味着:
-
mysqldump仍能导出逻辑结构,但物理备份(如rsync或 xtrabackup)必须显式包含这些外部.ibd文件 - 若用
FLUSH TABLES ... FOR EXPORT做可传输表空间(TTS),必须确保.ibd和.cfg文件配对完整,且表空间未被修改过 - 删除表空间前,必须先将所有关联表移出(
ALTER TABLE t TABLESPACE innodb_system),否则报ERROR 3137 (HY000): Cannot delete a tablespace that is being used by one or more tables
真正麻烦的从来不是命令怎么写,而是表空间路径分散后,备份脚本漏掉某个 .ibd,恢复时才发现数据“消失”了。











