CREATE TABLE ... SELECT 仅复制数据并反推结构,丢失主键、索引、AUTO_INCREMENT等;保结构必须用 CREATE TABLE ... LIKE + INSERT INTO ... SELECT。

CREATE TABLE ... SELECT 能最快完成结构+数据复制,但会丢主键、索引、AUTO_INCREMENT、NOT NULL、默认值和字符集——它不是克隆,只是“按结果建表”。真要保结构,必须分两步:CREATE TABLE ... LIKE + INSERT INTO ... SELECT。
用 CREATE TABLE ... SELECT 时为什么查重失效、插入报错
这条语句不读原表元数据,而是扫描 SELECT 结果反推列定义。常见翻车点包括:
-
Field 'id' doesn't have a default value:原表id INT AUTO_INCREMENT PRIMARY KEY,新表变成普通INT,没自增也没默认值 - 唯一索引消失:
UNIQUE KEY idx_email (email)不会被创建,重复邮箱可成功插入 - 字符集降级:跨库执行时,新表可能变成
latin1_swedish_ci,中文存进去就乱码 - 生成列或
CHECK约束直接报错退出,语句中断
为什么 CREATE TABLE ... LIKE 是结构保真度最高的原生方案
它直接读取原表的元数据,逐字段、逐索引重建,但要注意能力边界:
- ✅ 复制:
NOT NULL、DEFAULT、AUTO_INCREMENT、所有索引(主键/唯一/全文)、CHARSET、COLLATE、自增起始值 - ❌ 不复制:
FOREIGN KEY、触发器、表注释、分区定义、ROW_FORMAT(部分版本) - ⚠️ 显式报错:
ERROR 1050 (42S01): Table 'xxx' already exists,目标表存在就失败,不覆盖
LIKE + INSERT SELECT 组合操作的实际卡点
这是生产环境最稳妥的全量复制路径,但两步之间有隐性依赖:
-
INSERT INTO new_t SELECT * FROM old_t要求字段顺序、数量、类型严格一致;否则得显式写字段:INSERT INTO new_t (id, name) SELECT id, name FROM old_t - 大表导入前建议调大会话参数:
SET SESSION innodb_log_file_size = 256M,避免撑爆日志文件 - 跨库复制不支持
db1.t1 LIKE db2.t2语法,必须先USE db2或写成CREATE TABLE db2.new_t LIKE db1.old_t - 若原表有
COMMENT,需手动补:ALTER TABLE new_t COMMENT = '用户信息表'
字符集与排序规则最容易被忽略的陷阱
即使用了 LIKE,新表也可能“看起来一样,实际不同”:
- 执行前检查:
SHOW VARIABLES LIKE 'character_set_database'是否与原表一致(可用SELECT DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'your_db'验证) - 会话级变量如
collation_connection会影响列定义推导,尤其在低版本客户端连接时 -
utf8mb4_0900_as_cs和utf8mb4_0900_ai_ci表面都是 utf8mb4,但排序行为完全不同,查重、ORDER BY 结果可能出错
真正需要“结构+数据”且后续要写入的场景,别贪快。两步法多敲一次回车,换来的是 SHOW CREATE TABLE 里清清楚楚的 PRIMARY KEY 和 KEY 定义——这点确定性,在线上环境比省那几秒重要得多。


















