CREATE TABLE ... SELECT 快但不保约束,因按查询结果反推列定义,丢失主键、自增、非空、索引、默认值及字符集;应优先用 CREATE TABLE ... LIKE + INSERT 实现结构保真复制。

CREATE TABLE ... SELECT 为什么快但不保约束
因为这条语句本质是“按查询结果反推列定义”,不是读取原表元数据。它能一条 SQL 完成建表+插数据,但会丢掉:PRIMARY KEY、AUTO_INCREMENT、NOT NULL(部分 MySQL 版本)、所有索引、默认值、字符集继承也可能异常。
常见翻车现场:
-
Field 'id' doesn't have a default value:原表id INT AUTO_INCREMENT PRIMARY KEY,新表变成普通INT - 查重失效:
UNIQUE KEY idx_email (email)消失,插入重复邮箱不报错 - 跨库复制时字符集降级成
latin1_swedish_ci,导致中文乱码或排序异常 - 遇到生成列(
GENERATED COLUMN)或CHECK约束直接报错退出
什么时候可以放心用 CREATE TABLE ... SELECT
适合对约束无强依赖的临时场景,比如导出分析快照、ETL 中间表、备份归档(后续不写入)。
实操建议:
- 确认目标库没同名表,否则报错
ERROR 1050 (42S01): Table 'xxx' already exists - 若只要部分字段,显式写出列名:
CREATE TABLE new_t SELECT id, name, email FROM old_t,避免隐式类型转换 - 若要筛选数据,
WHERE必须写在SELECT子句里:CREATE TABLE new_t SELECT * FROM old_t WHERE status = 'active' - 大表慎用:该语句是单事务执行,可能撑爆
innodb_log_file_size或触发长事务告警
想保留主键和索引?别用 AS SELECT
CREATE TABLE ... LIKE 才是结构保真度最高的原生方案,它复制:NOT NULL、DEFAULT、AUTO_INCREMENT、所有索引(主键/唯一/全文)、字符集、排序规则、自增起始值。
但它不复制:FOREIGN KEY、触发器、表注释、分区定义、部分存储引擎参数(如 ROW_FORMAT)。
关键细节:
- 执行前确保目标库无同名表,否则直接报错退出
- 外键不会被复制,但若新表要引用其他表,必须先建好被引用表,否则后续
INSERT报ERROR 1452 (23000) - 若原表有
COMMENT,需手动补:ALTER TABLE new_t COMMENT = 'xxx'
组合操作:LIKE + INSERT 的实际卡点
这是生产环境最稳妥的全量复制路径,但两步之间有隐藏依赖。
必须注意:
-
INSERT INTO new_t SELECT * FROM old_t要求两表字段顺序和类型严格兼容;若字段数不等或类型不匹配,得显式列出字段:INSERT INTO new_t (id, name) SELECT id, name FROM old_t - 大表导入前建议调大会话参数:
SET SESSION sort_buffer_size = 268435456(256MB),加速索引重建 - 如果原表有
TIMESTAMP列且含DEFAULT CURRENT_TIMESTAMP,新表中该默认值会被复制,但ON UPDATE CURRENT_TIMESTAMP不会——这点容易被忽略 - 字符集不一致时,
INSERT可能触发隐式转换警告,需提前检查SHOW CREATE TABLE old_t和SHOW CREATE TABLE new_t的CHARSET是否一致


















