CREATE TABLE ... SELECT 复制数据但丢失约束、索引等结构;CREATE TABLE ... LIKE 精确复制结构但无数据;最佳实践是二者组合:先 LIKE 再 INSERT SELECT。

CREATE TABLE ... SELECT 会复制数据,但结构可能意外变形
用 CREATE TABLE new_table SELECT * FROM old_table 确实能一键复制数据和结构,但它本质是“基于查询结果建表”,所以所有列都按 SELECT 表达式的推导类型生成,不继承原表的:
-
NOT NULL约束会被丢弃(除非显式写SELECT col+0 AS col这类强制非空表达式) - 默认值(
DEFAULT)完全丢失 - 自增(
AUTO_INCREMENT)不会复制,新表对应列为普通整型 - 索引、主键、外键、注释一概不复制
- 如果原表有计算列或虚拟列,
SELECT *会把它们展开为普通值,新表里变成普通存储列
适合场景:快速导出一份带数据的快照用于临时分析,不关心约束和索引是否一致。
CREATE TABLE ... LIKE 只复制结构,零数据,但保留全部定义
CREATE TABLE new_table LIKE old_table 是真正意义上的结构克隆 —— 它直接读取原表的元数据,逐字复刻:
- 所有列定义(含
NOT NULL、DEFAULT、AUTO_INCREMENT)完整保留 - 所有索引(包括主键、唯一、全文、空间索引)原样重建
- 表选项如
ENGINE、CHARSET、COLLATE、COMMENT全部继承 - 但明确不复制任何数据行,新表为空
常见误用:以为 LIKE 能复制分区定义 —— 实际上 MySQL 8.0.24 之前它不复制分区信息,需额外 SHOW CREATE TABLE 手动补全。
想又快又全?分两步最稳:LIKE + INSERT SELECT
既要结构精确,又要数据到位,就别贪一步到位。标准做法就是组合使用:
CREATE TABLE new_table LIKE old_table; INSERT INTO new_table SELECT * FROM old_table;
这比单条 CREATE ... SELECT 多一次语句,但换来的是可预期的结构一致性。注意两点:
- 如果原表数据量极大,
INSERT SELECT期间会持有源表的 MDL 读锁(MySQL 5.6+),可能阻塞 DDL;可考虑加LOW_PRIORITY或分批次INSERT ... LIMIT - 目标表若已有数据,需先
TRUNCATE或加REPLACE INTO,但后者依赖唯一键,且会触发删除+插入逻辑,影响自增值 - 跨库复制时,
LIKE不支持库名前缀(db1.tbl1 LIKE db2.tbl2语法非法),必须先USE db2或用CREATE TABLE db2.new_tbl LIKE db1.old_tbl
容易被忽略的字符集与排序规则陷阱
即使用了 LIKE,如果原表和当前会话的默认字符集不一致,新表仍可能“看起来一样,实际不同”:
- 执行
CREATE TABLE ... LIKE前,检查SHOW VARIABLES LIKE 'character_set_database'是否与原表一致 - 原表用
utf8mb4_0900_as_cs,而当前库默认是utf8mb4_0900_ai_ci,新表的COLLATE会变成后者 ——LIKE复制的是列定义,但未显式指定COLLATE的列会 fallback 到库级默认 - 验证方式:对比
SHOW CREATE TABLE old_table和SHOW CREATE TABLE new_table中每列的COLLATE子句是否完全一致
真正可靠的跨库结构迁移,不能只靠 LIKE,得从 SHOW CREATE TABLE 输出中提取建表语句,手动替换库名和表名后再执行。


















