Mysql更新百万历史数据

场景

目前在main库里有一张main_test表,数据大约1000万

CREATE TABLE
    main.main_test
    (
        id BIGINT NOT NULL COMMENT '主键ID',
        name VARCHAR(100) COMMENT '名称',
        PRIMARY KEY (id)
    )
    ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='主表';

需求为给main_test表添加一code列

ALTER TABLE main_test ADD COLUMN code  VARCHAR(60) COMMENT '代码' AFTER id ;

然后从另一个数据库sla的表slave_test关联更新main_test表的code,具体关联关系为

UPDATE main.main_test mt INNER JOIN sla.slave_test st ON mt.name = st.name SET mt.code = st.code;

问题

  1. main_test表与slave_test表不在同一个库,因此不能直接关联更新
  2. 即使在同一个库,但是main_test表数据量大,并且name字段没有索引,也不能临时添加索引,强行在生产环境更新会因为锁表阻塞导致应用雪崩

解决方案

1、在main库创建临时表main_test_tmp

CREATE TABLE
    main.main_test_tmp
    (
        id INT AUTO_INCREMENT PRIMARY KEY NOT NULL COMMENT '主键ID',
        test_id BIGINT COMMENT 'main_test表主键', 
        name VARCHAR(100) COMMENT '名称',
        code VARCHAR(60) COMMENT '代码'
    )
    ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='主表';

2、查询slave_test表并导出到文件
建议导出为insert sql,并检查 name, code 值是否包含单引号’,将一个单引号’替换成两个单引号’,如’替换成’’,防止sql注入攻击。目标表修改为main_test_tmp

SELECT name, code FROM sla.slave_test WHERE code IS NOT NULL AND name IS NOT NULL

3、向main_test_tmp表插入文件中的sql
4、给main_test_tmp表name字段创建前缀索引
因为name字段长度为100,一些数据库对索引长度有限制,并且name字段的前10个字符唯一度已经很高

ALTER TABLE main_test_tmp ADD INDEX (name(10));

5、更新main_test_tmp表的test_id字段

UPDATE main_test_tmp mtt INNER JOIN main_test mt ON mtt.name = mt.name SET mtt.test_id = mt.id
WHERE mt.code IS NULL;

6、给main_test_tmp表test_id字段创建索引
注意,第6步只执行一次,以后不再执行

ALTER TABLE main_test_tmp ADD INDEX  (test_id);

7、查询main_test_tmp表是否存在test_id字段不为null的数据

SELECT * FROM main_test_tmp WHERE test_id IS NOT NULL LIMIT 1;

如果存在,则继续下一步,否则执行第11步。

8、更新main_test表的code字段

UPDATE main_test mt INNER JOIN main_test_tmp mtt ON mt.id = mtt.test_id SET mt.code = mtt.code
WHERE mtt.test_id IS NOT NULL;

9、main_test_tmp表test_id字段都更新为null

UPDATE TABLE main_test_tmp SET test_id = null;

10、回到第5步,重复步骤(需要跳过第6步)
11、main_test表的code字段更新完毕,删除临时表main_test_tmp

DROP TABLE main_test_tmp;

说明

以上只考虑了main_test表name字段重复的情况。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值