结论:MySQL异构迁移需分四类处理——时间类型须按UTC显式转换并规避自动更新;引擎切换应禁用ALTER而用重建表+pt工具;TEXT/BLOB需实测长度并按目标库特性截断或压缩;字符集必须全程显式指定utf8mb4及对应collation,存量乱码需人工清洗。

MySQL异构迁移时 datetime 和 timestamp 行为不一致怎么办
直接说结论:datetime 和 timestamp 在跨引擎(比如迁到 PostgreSQL 或 ClickHouse)或跨版本 MySQL 时,时区处理、默认值逻辑、自动更新机制全都不一样,不是简单替换字段类型就能跑通。
常见错误现象是数据看起来“没丢”,但查询结果时间偏移 8 小时,或者插入空值后变成 0000-00-00 00:00:00 被截断甚至报错。
-
timestamp总是受TZ影响,写入时转为 UTC 存储,读取时再转回会话时区;datetime是“所见即所得”,不转换 - MySQL 5.6+ 默认开启
explicit_defaults_for_timestamp,旧库关了这个配置的话,NULL列可能被悄悄改成CURRENT_TIMESTAMP - PostgreSQL 没有原生
timestamp的自动更新语义,得靠触发器或DEFAULT NOW()+ 应用层维护 - ClickHouse 的
DateTime类型不支持时区,存的是本地时间戳整数,迁移时必须提前统一时区并显式转换
实操建议:导出前先查 SHOW CREATE TABLE 看字段定义,重点核对 DEFAULT、ON UPDATE、NULL 属性;导入目标库前,把所有 timestamp 字段按 UTC 显式转换成字符串再写入,避免依赖目标库的隐式行为。
MyISAM 表迁到 InnoDB 后出现锁表或性能骤降
这不是“换引擎就完事”的操作——MyISAM 是表级锁、无事务、不支持外键;InnoDB 是行级锁、MVCC、强制事务一致性。直接改 ENGINE=InnoDB 可能导致应用卡死或查询变慢。
典型表现是批量更新变慢、SELECT ... FOR UPDATE 报死锁、或者 ALTER TABLE 执行几小时不结束。
- MyISAM 允许
NULL做主键,InnoDB 不允许;迁移前得补NOT NULL约束 - MyISAM 的全文索引语法和行为跟 InnoDB 不兼容,
MATCH ... AGAINST可能直接报错 - InnoDB 默认
innodb_file_per_table=ON,但老 MyISAM 表可能用了共享表空间,迁移后磁盘占用反而飙升 - 大表执行
ALTER TABLE ... ENGINE=InnoDB会锁整个表,建议用pt-online-schema-change或在业务低峰分批做
实操建议:先用 mysqldump --no-create-info 导出数据,再用 CREATE TABLE ... ENGINE=InnoDB 新建结构,最后导入;别依赖 ALTER 一键切换,尤其当表超过 1GB 时。
TEXT/BLOB 字段在不同目标库中长度限制差异大
MySQL 的 TEXT 最大 64KB,MEDIUMTEXT 是 16MB,LONGTEXT 是 4GB;但 PostgreSQL 的 TEXT 虽无硬上限,却对索引长度有限制(默认 2712 字节);ClickHouse 的 String 类型虽然够大,但排序/去重时会因长度爆炸性消耗内存。
MySQL 数据库管理技能,能够通过自然语言查询和管理数据库,支持 SELECT/INSERT/UPDATE/DELETE、表管理、备份恢复等操作。当用户提及 MySQL、数据库查询、建表或数据备份时使用此技能。
容易踩的坑是:迁移脚本没检查字段实际最大长度,直接映射过去,结果 PG 报 index row requires 12345 bytes, maximum size is 8191,或者 ClickHouse 写入时报 Memory limit (for query) exceeded。
- 先运行
SELECT MAX(LENGTH(col_name)) FROM table_name统计真实长度分布 - PostgreSQL 中若字段常用于
WHERE或ORDER BY,考虑加substring(col_name, 1, 200)截断建索引 - ClickHouse 若字段只是日志类内容,用
LowCardinality(String)或Nullable(String)更省资源 - 别盲目把 MySQL 的
LONGTEXT全部映射成 PG 的TEXT,有些其实该拆成 JSONB + 外部存储
实操建议:用 information_schema.COLUMNS 查原始定义,再结合 SELECT ... LENGTH() 样本分析,按需切分或压缩,而不是照单全收。
字符集与排序规则(collation)混用导致乱码或查询失效
MySQL 支持 utf8mb4,但很多老库还在用 utf8(其实是 utf8mb3),而 PostgreSQL 默认是 UTF8,ClickHouse 默认是 UTF-8 编码但排序规则只认 binary。迁移时不显式指定,中文、emoji、带音调的越南文全都会出问题。
最隐蔽的问题是:数据看着正常,但 WHERE name = '张三' 查不到,因为源库用 utf8mb4_unicode_ci,目标库用 en_US.utf8,排序权重不同,等于判断失败。
- 导出时加
--default-character-set=utf8mb4,避免 mysqldump 自动降级 - 目标库建表必须显式写
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,不能依赖数据库默认值 - PostgreSQL 没有全局 collation,每个字段可单独设
COLLATE "zh_CN.utf8",但必须提前装好对应 locale - ClickHouse 的
CollapsingMergeTree对字符串排序极度敏感,collation 不一致会导致合并异常
真正麻烦的是存量数据已混入多种编码,这时候光改 DDL 没用,得用 CONVERT(... USING ...) 配合 CAST 逐字段清洗——这步没法自动化,必须人工抽样验证。










