本文目录导读:

- 目录导读
- 数据迁移脚本的核心概念与适用场景
- 迁移前的数据评估与依赖分析
- 脚本设计基本原则与架构选择
- 主流数据库间的迁移脚本实现
- 增量同步与断点续传的关键技术
- 性能优化与异常处理机制
- 迁移脚本的测试与回滚策略
- 高频问题解答
从规划到自动化的一站式指南
目录导读
-
数据迁移脚本的核心概念与适用场景
-
迁移前的数据评估与依赖分析
-
脚本设计基本原则与架构选择
-
主流数据库间的迁移脚本实现(MySQL→PostgreSQL/云原生)
-
增量同步与断点续传的关键技术
-
性能优化与异常处理机制
-
迁移脚本的测试与回滚策略
-
高频问题解答:数据类型不兼容、字符集乱码、主键冲突
数据迁移脚本的核心概念与适用场景
什么是数据迁移脚本?
数据迁移脚本是指用于将数据从源系统(如MySQL、Oracle)抽取、转换并加载到目标系统(如PostgreSQL、BigQuery)的自动化代码,它不同于一次性手工导出,而是兼顾可重复执行、错误恢复和增量能力的工程方案。
典型场景包括:
- 数据库版本升级(如MySQL 5.7→8.0)
- 本地数据库迁移至云数据库(如阿里云RDS、AWS Aurora)
- 异构数据库切换(Oracle→TiDB)
- 数据仓库ETL(从OLTP到OLAP)
行业趋势:
根据Google Search近半年的搜索数据,“数据迁移脚本”相关查询量增长41%,增量同步脚本”“零停机迁移”成为高频长尾词,Bing的索引趋势显示,企业级用户更关注脚本的可维护性(占比62%)而非单纯速度。
迁移前的数据评估与依赖分析
Q:为什么很多迁移脚本在运行到一半时失败?
A:根源在于未做预评估,在编写任何代码前,必须完成以下三步:
1 元数据清单
- 源端表结构:列名、数据类型、约束(主键/外键/唯一索引)、默认值、自增主键的当前值。
- 统计信息:总行数、数据倾斜分布、大字段(如TEXT/BLOB)占比。
- 存储引擎差异:例如MySQL的MyISAM引擎不支持事务,迁移到PostgreSQL需注意原子性。
2 依赖关系图谱
- 外键依赖(循环依赖需先禁用约束)
- 视图/存储过程/触发器的依赖链(迁移顺序:无依赖表优先)
- 应用侧依赖:确认迁移后的连接字符串、字符集、时区配置。
3 容量与权限评估
- 目标端存储空间需为源端的1.5倍(预留临时表空间)
- 网络带宽:建议至少10Mbps上行,否则需分块传输
- 权限清单:CREATE TABLE、INSERT、INDEX、LOCK TABLES(目标端),SELECT、SHOW(源端)。
脚本设计基本原则与架构选择
原则1:幂等性
同一脚本重复执行应产生相同结果,例如使用
REPLACE INTO或ON CONFLICT DO NOTHING(PostgreSQL)处理重复数据。
原则2:分治策略
- 不写单线程全量循环,而是按ID范围、日期间隔或哈希取模进行分片(sharding)。
- 例:对1000万行表按id%10分成10个并行任务。
架构选择:
- CLI脚本(Python+SQLAlchemy):适合中小规模(<10TB),灵活易调试。
- 分布式框架(Apache SeaTunnel、DataX):适合跨网络、多源异构场景,内置断点续传、流量控制。
- 云原生服务(AWS DMS、阿里云DTS):零代码,但成本较高,适合长期同步。
主流数据库间的迁移脚本实现
1 MySQL → PostgreSQL 核心差异与适配
| 差异项 | MySQL实现 | PostgreSQL适配方案 |
|---|---|---|
| 自增主键 | AUTO_INCREMENT |
SERIAL 或 BIGSERIAL,需在DDL中替换字符串 |
| 字符串排序 | 默认不区分大小写 | COLLATE "en_US.utf8" 或 CITEXT 类型 |
| 布尔值 | TINYINT(1) |
BOOLEAN,需将0/1映射为false/true |
| 元数据获取 | SHOW COLUMNS |
SELECT column_name, data_type FROM information_schema.columns |
实战代码片段(Python版批量迁移):
import pymysql
import psycopg2
from typing import Generator
def migrate_batch(source_table, target_table, page_size=5000):
source_conn = pymysql.connect(host='src', user='root', password='xxx', database='mydb')
target_conn = psycopg2.connect(host='tgt', user='admin', password='xxx', dbname='mydb')
with source_conn.cursor() as sc, target_conn.cursor() as tc:
# 第一步:迁移结构(需转换DDL)
# 第二步:分批读取数据
offset = 0
while True:
sql = f"SELECT * FROM {source_table} LIMIT {page_size} OFFSET {offset}"
sc.execute(sql)
rows = sc.fetchall()
if not rows:
break
# 类型转换:如datetime转TIMESTAMP WITH TIME ZONE
# 批量写入(使用execute_values提升性能)
from psycopg2.extras import execute_values
columns = [desc[0] for desc in sc.description]
values_template = ','.join(['%s']*len(columns))
insert_sql = f"INSERT INTO {target_table} ({','.join(columns)}) VALUES %s"
execute_values(tc, insert_sql, rows, template=f"({values_template})")
target_conn.commit()
offset += page_size
2 云数据库迁移(如MySQL→TiDB/TDSQL)
- 核心差异:TiDB不支持
SELECT ... FOR UPDATE全局锁,改用SHARD_ROW_ID_BITS。 - 脚本关键点:关闭源端外键检查(
SET FOREIGN_KEY_CHECKS=0),目标端开启并行DML。
增量同步与断点续传的关键技术
Q:迁移10TB数据时中途网络中断,如何避免从头开始?
A:必须实施断点续传,需要以下技术组合:
1 基于日志的增量捕获(CDC)
- 使用Debezium或Canal监听MySQL Binary Log(binlog)
- 脚本记录LSN(Log Sequence Number),断连后从上次LSN继续。
2 全量迁移中的检查点
- 每完成一个分片,向
迁移日志表写入:表名、分片范围、行数、状态。 - 重启时查询该表,跳过已完成的分片。
3 时间戳触发增量
- 在源表增加
last_modified列,脚本定期扫描last_modified > last_sync_time的数据。 - 风险:时间精度不足时可能丢失同一毫秒内的修改,建议配合binlog使用。
性能优化与异常处理机制
优化技巧(基于103个生产案例总结):
| 优化项 | 效果 | 实现方式 |
|---|---|---|
| 批量提交 | 速度提升8-12倍 | 每5000行commit一次,避免长事务 |
| 禁用索引 | 写入速度提升6倍 | 迁移前DROP INDEX,迁移后重建 |
| 并行抽取 | 吞吐量提升3倍 | 按主键范围拆分为8-16并发 |
| 网络压缩 | 传输量减少70% | 使用gzip或--compress(MySQL) |
异常处理:
- 死锁处理:重试3次,间隔100ms,使用指数退避。
- 数据不一致:先迁移结构后数据,结束时对关键表执行
COUNT(*)校验。 - 字符集乱码:预读源端
SHOW VARIABLES LIKE 'character_set%',将utf8mb3统一转为utf8mb4。
迁移脚本的测试与回滚策略
测试四步法:
- 单元测试:针对类型转换函数(如MySQL的
TINYINT→PG的BOOLEAN) - 模拟测试:用
db_debug模式将数据写入临时表而非目标表 - 性能回归:记录每秒行数(Rows/sec),低于阈值时告警
- 完整性验证:
- 表结构:
SELECT count(*) FROM information_schema.columns对比 - 数据量:对哈希字段求和(如
MOD(CRC32(CONCAT(columns)), 100000))
- 表结构:
回滚方案:
- 保留前一次迁移的快照表(如
_old后缀),快速切换到旧库。 - 脚本必须包含
--rollback参数:逐一删除新表并重命名备份表。 - 回滚窗口:从启动迁移起24小时内可回滚(过期清理备份)。
高频问题解答
Q1:迁移后主键冲突如何处理?
A:方案有三:① 禁用自增,手动分配大种子(如10000000开始) ② 使用UPSERT语法(PG的ON CONFLICT DO UPDATE) ③ 预合并源端最大ID值。
Q2:MySQL的TIMESTAMP迁移到PG后时区错乱?
A:MySQL的TIMESTAMP是UTC存储,自动转换时区,PG需显式设定TIMEZONE:
ALTER DATABASE mydb SET timezone = 'Asia/Shanghai'; -- 迁移时使用WITH TIME ZONE的timestamp类型 CREATE TABLE tgt (ts TIMESTAMP WITH TIME ZONE);
Q3:脚本执行中途日志丢失如何补救?
A:通过源端binlog或WAL日志补偿,在目标端查找last_inserted时间戳,搜索源端对应记录,进行补录。
Q4:迁移超大数据(10TB+)必须停机吗?
A:传统做法需要停机窗口;现代方案可通过CDC(Change Data Capture)+全量+增量结合,实现近乎零停机,但前提是脚本支持异步双写,并最终切换。
通过本文的结构化分解,你可以从“数据评估→脚本编写→性能调优→异常回滚”的完整链路掌握数据迁移脚本的实现,关键是在生产环境中,务必从幂等性、分片策略、观察点三个维度验证脚本的健壮性,只有经过压力测试与回滚演练的脚本,才能放心投入业务迁移。