CREATE TABLE ... LIKE 最可靠复制表结构和索引,保留字段定义、主键、各类索引、自增、默认值、字符集、引擎及生成列,但不复制外键约束;而 CREATE TABLE ... AS SELECT 仅复制字段类型和数据,丢失所有索引与约束。

用 CREATE TABLE ... LIKE 复制结构和索引最可靠
直接执行 CREATE TABLE 新表名 LIKE 原表名; 就能完整复制字段定义、主键、唯一索引、普通索引、自增属性、默认值、字符集和存储引擎——但不复制外键约束(MySQL 8.0.19+ 可通过 FOREIGN_KEY_CHECKS=0 配合手动重建,但默认不带)。
常见错误是误用 CREATE TABLE ... AS SELECT,它只复制字段类型和数据,所有索引、主键、AUTO_INCREMENT 全丢,后续查不到索引或插入报错才反应过来。
- 执行前先确认原表引擎:
SHOW CREATE TABLE 原表名;,避免跨引擎复制(如原表是InnoDB,目标库默认MyISAM) - 若原表含外键,
LIKE不会复制,需单独导出:SELECT CONSTRAINT_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = '原表名' AND CONSTRAINT_SCHEMA = '数据库名'; - 跨库复制时写法是:
CREATE TABLE 目标库.新表名 LIKE 源库.原表名;,注意权限是否覆盖两个库
为什么不用 SHOW CREATE TABLE + 手动改名
虽然 SHOW CREATE TABLE 原表名; 返回的 SQL 最精确,但人工修改表名容易出错:漏改反引号、多改了注释里的旧表名、引擎参数被截断、字符集声明位置偏移导致语法错误。尤其在自动化脚本或批量操作中,这种“复制粘贴改名”方式维护成本高、不可靠。
它真正适合的场景是:需要微调结构(比如删掉某个索引、改某个字段为 NOT NULL),或者目标库版本/配置与源库差异大(如从 5.7 升级到 8.0 后需显式指定 sql_mode)。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 返回结果里
CREATE TABLE语句末尾可能带/*!...*/注释,直接执行没问题;但若中间有ALGORITHM=INSTANT等新版特性,在老版本上会报错 - 如果原表用了生成列(
GENERATED ALWAYS AS),LIKE能保留,但SHOW CREATE TABLE输出的语句必须完整执行,不能只抄CREATE TABLE部分而漏掉列定义细节
复制后验证索引是否真生效
执行完 CREATE TABLE 新表名 LIKE 原表名; 后,别急着插数据。立刻用两条命令交叉验证:
-
SHOW INDEX FROM 新表名;—— 对比原表的索引数量、列顺序、是否唯一、是否为主键 -
EXPLAIN SELECT * FROM 新表名 WHERE 索引字段 = 'xxx';—— 看key列是否命中预期索引,而不是NULL或ALL - 特别注意:如果原表有前缀索引(如
INDEX idx_name (name(10))),LIKE会完整保留长度声明,但AS SELECT会丢成全字段索引,导致查询性能下降
大表结构复制时的隐形开销
CREATE TABLE ... LIKE 是 DDL 操作,在 InnoDB 中会持有元数据锁(MDL),阻塞对原表的 DML(INSERT/UPDATE/DELETE),但不会锁住整个表数据。不过如果原表正被长事务占用,这个 DDL 会卡住等待,表现为命令一直没响应。
- 可先查是否有活跃长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 60; - 线上操作建议加超时控制(MySQL 8.0.12+ 支持):
SET lock_wait_timeout = 10;,再执行LIKE语句 - 不要在高峰期执行;如果原表是分区表,
LIKE会复制分区定义,但不会复制分区数据——这点常被忽略,以为“结构复制完了就等于能用了”










