一、MySQL 大表分批次更新存储过程

1. 问题背景

由于爬虫同事粗心所致,导致数据库表core_comparison_platform_goods_item(总数据量382w)出现约14.2w条photo_url的http前缀重复,导致APP商品数据图片空白。
image.png
TRX0$79)CDFKOL`JTVD24_O.png
出现问题数据量:14.2w,单次count查询耗费约60s
![W$AYL22KEIU[JUO890%7.png

2. 预期目标

从core_comparison_platform_goods_item表中382w数据中,update 14.2w问题数据,即:将问题数据photoUrl字段http:http:替换为http:。
由于该表是业务非常活跃的表,如果仅仅通过一个update语句,进行一次性全量更新,将导致锁表问题(至少锁表一分多钟,影响APP业务)。故而,最终敲定方案为:分批次更新,每更新批次数据量为5条,每一个批次一个事务。

3. 相关实现

3.1 建立日志表

  1. CREATE TABLE error_log
  2. (
  3. id INT AUTO_INCREMENT
  4. PRIMARY KEY,
  5. type VARCHAR(128) NULL,
  6. title VARCHAR(128) NULL,
  7. code VARCHAR(128) NULL,
  8. message TEXT NULL,
  9. create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NULL
  10. );

3.2 数据处理存储过程

  1. DROP PROCEDURE IF EXISTS big_table_update;
  2. CREATE PROCEDURE big_table_update()
  3. BEGIN
  4. # 每批次处理的记录条数,可自行修改
  5. DECLARE v_update_limit INT(10) DEFAULT 5;
  6. DECLARE v_primary_key_start, v_primary_key_end BIGINT(20) DEFAULT 0;
  7. # 异常捕获
  8. DECLARE v_error_code CHAR(5) DEFAULT '00000';
  9. DECLARE v_error_message VARCHAR(512) DEFAULT '';
  10. DECLARE EXIT HANDLER FOR SQLEXCEPTION
  11. BEGIN
  12. GET DIAGNOSTICS CONDITION 1 v_error_code= RETURNED_SQLSTATE,v_error_message= MESSAGE_TEXT;
  13. INSERT INTO error_log(type, title, code, message) VALUES ('skl_photoUrl_update', 'big_table_update', v_error_code, v_error_message);
  14. COMMIT;
  15. END;
  16. WHILE EXISTS(SELECT 1 FROM core_comparison_platform_goods_item skl WHERE skl.photo_url like 'http:http:%' and skl.item_id > v_primary_key_start)
  17. DO
  18. BEGIN
  19. START TRANSACTION;
  20. # 查询当前批次处理的最大的主键
  21. SELECT item_id INTO v_primary_key_end FROM (SELECT item_id 'item_id' FROM core_comparison_platform_goods_item
  22. WHERE photo_url like 'http:http:%' and item_id > v_primary_key_start
  23. LIMIT v_update_limit) temp ORDER BY temp.item_id DESC LIMIT 1;
  24. ############################### 自定义更新数据语句【开始】###########################################################
  25. UPDATE core_comparison_platform_goods_item SET photo_url = replace( photo_url, 'http:http:', 'http:' )
  26. WHERE item_id BETWEEN v_primary_key_start AND v_primary_key_end and photo_url like 'http:http:%';
  27. ############################### 自定义更新数据语句【结束】###########################################################
  28. # 重新设置主键起始值
  29. SET v_primary_key_start = v_primary_key_end + 1;
  30. COMMIT;
  31. # 暂停10毫秒
  32. SELECT SLEEP(0.010);
  33. END;
  34. END WHILE;
  35. ROLLBACK;
  36. END;

3.3 执行存储过程

  1. # 执行存储过程
  2. CALL big_table_update();