数据迁移最佳实践:如何避免ALTER TABLE锁表惨案?
最近在重构商城插件时踩了个大坑:给200万数据的订单表新增字段时,整个系统卡死15分钟。分享几个避免锁表的核心方案:
方案1:影子表+数据同步
先创建新结构表,用触发器同步数据,最后rename切换:
CREATE TABLE orders_new LIKE orders;
ALTER TABLE orders_new ADD COLUMN invoice_status TINYINT;
-- 创建三个触发器同步INSERT/UPDATE/DELETE
RENAME TABLE orders TO orders_old, orders_new TO orders;
方案2:pt-online-schema-change工具
Percona的这个神器本质也是影子表方案,但自动处理了:
- 触发器维护
- 增量数据追赶
- 原子切换
pt-online-schema-change --alter "ADD COLUMN refund_id VARCHAR(32)" D=test,t=orders
方案3:版本化迁移(适合插件开发)
在插件install时仅建基础表,后续通过升级脚本追加:
// 1.0.0安装脚本
CREATE TABLE orders (id INT, price DECIMAL...);
// 1.1.0升级脚本
if (!schemaHasColumn('orders', 'coupon_id')) {
$this->addColumn('orders', 'coupon_id VARCHAR(32) AFTER price');
}
实测百万级数据表: - 直接ALTER:锁表12分钟 - 影子表方案:平均300ms阻塞 - pt-osc:约500ms阻塞
最后提醒:永远先在沙箱环境测试迁移脚本!我们在预发布环境模拟了3次数据量翻倍才敢上生产。

