优先用 CREATE TABLE ... SELECT 快速复制表结构和数据,但会丢失主键、自增、索引、NOT NULL 等约束;需完整定义时,必须用 CREATE TABLE ... LIKE + INSERT INTO ... SELECT 两步实现。

直接说结论:想快速复制表结构和数据,优先用 CREATE TABLE ... SELECT;但若需保留主键、索引、自增值等完整定义,必须拆成 CREATE TABLE ... LIKE + INSERT INTO ... SELECT 两步。
为什么 CREATE TABLE new_t SELECT * FROM old_t 看似快却容易翻车
这条语句确实一条 SQL 就搞定结构+数据,但底层行为是“按查询结果推导列定义”,所以会丢失:PRIMARY KEY、AUTO_INCREMENT、NOT NULL(部分版本)、索引、默认值、字符集继承可能异常。实测中常见问题包括:
- 新表
id字段变成普通INT,没了自增,插入时爆错Field 'id' doesn't have a default value - 原表有
UNIQUE KEY idx_email (email),新表里完全没这个索引,查重失效 - 原表用
utf8mb4_unicode_ci,新表可能降级成latin1_swedish_ci(尤其跨库时) - 如果原表有生成列(generated column)或检查约束(CHECK),该语句直接报错不执行
CREATE TABLE ... LIKE 能复制什么、不能复制什么
CREATE TABLE new_t LIKE old_t 是结构复制的“保真度最高”原生方案,但必须清楚它的能力边界:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- ✅ 复制:所有列定义(含
NOT NULL、DEFAULT、AUTO_INCREMENT)、主键、唯一索引、普通索引、全文索引、字符集(CHARSET)、排序规则(COLLATE)、自增起始值(AUTO_INCREMENT=xxx) - ❌ 不复制:外键约束(
FOREIGN KEY)、触发器(TRIGGER)、表注释(COMMENT)、分区定义(PARTITION BY)、存储引擎参数(如ROW_FORMAT有时会丢) - ⚠️ 注意:
LIKE不校验目标库是否存在同名对象,若new_t已存在,语句直接报错ERROR 1050 (42S01): Table 'new_t' already exists
组合操作:先 LIKE 再 INSERT SELECT 的实操要点
这是生产环境最稳妥的全量复制路径,但每一步都有细节要卡准:
- 确保目标库有足够空间——
INSERT INTO ... SELECT是单事务写入,大表会撑满innodb_log_file_size或触发长事务告警 - 若原表有外键引用其他表,
INSERT前需先在目标库建好被引用表,否则报错ERROR 1452 (23000): Cannot add or update a child row - 执行前建议加
SET SESSION sort_buffer_size = 268435456;(256MB),加速排序类索引重建(尤其带ORDER BY的SELECT) - 若只要部分数据,
WHERE条件必须写在INSERT的SELECT子句里,例如:INSERT INTO new_t SELECT * FROM old_t WHERE status = 'active'; - 字段数/类型不一致时,显式列出字段名,避免顺序错位:
INSERT INTO new_t (id, name, created_at) SELECT id, user_name, add_time FROM old_t;
什么时候该放弃 SQL,改用 mysqldump
当你要跨实例复制、或需保留外键/触发器/注释时,CREATE TABLE ... LIKE 就不够用了。此时直接上 mysqldump 更省心:
- 只导结构(含外键):
mysqldump -d --skip-triggers db_name table_name > struct.sql - 导结构+数据(带一致性快照):
mysqldump --single-transaction -t db_name table_name > data.sql - 关键点:生成的 SQL 文件里表名是硬编码的,必须手动替换——比如把
CREATE TABLE `old_t`改成CREATE TABLE `new_t`,漏改一个就建错表 - 导入前务必确认目标库字符集与源库一致,否则
mysqldump默认按连接字符集输出,可能引发乱码
真正容易被忽略的是锁行为:CREATE TABLE ... LIKE 会对原表加 MDL_SHARED_READ 锁,阻塞 DDL;而 INSERT INTO ... SELECT 在可重复读隔离级别下,会隐式开启事务并持有行锁——如果原表正在被高频更新,这两步都可能成为线上抖动源。别只盯着语法对不对,得看它在你实例里实际卡在哪里。

















