当前位置:首页 » 创享学习 » 不锁表执行SQL语句,每次处理500~1000条,并输出日志记录执行情况的操作方法

分类页和文章页“当前位置”下方广告(PC版),后台可以自由更改

不锁表执行SQL语句,每次处理500~1000条,并输出日志记录执行情况的操作方法

3°c 2026年06月25日 22:20 创享学习 0条评论
  移步手机端

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
不锁表执行SQL语句,每次处理500~1000条,并输出日志记录执行情况的操作方法摘要:

...

总字数:8820

SQL执行语句,不锁表,每次处理100~1000条,并输出日志记录执行情况的操作方法:

一键执行脚本(包含建表、过程、调用)

在 Navicat 的“新建查询”中(或直接在 MySQL 命令行工具中)完整复制并执行以下代码。
⚠️ 注意:执行前请务必把代码中的 

SQL
-- 1. 创建专门的迁移日志表 (用于查看进度和结果)CREATE TABLE IF NOT EXISTS pre_migration_log (
    id INT AUTO_INCREMENT PRIMARY KEY,
    log_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    process_type VARCHAR(50),
    start_id INT,
    end_id INT,
    affected_rows INT,
    status_msg VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- 2. 更改结束符,准备写入存储过程DELIMITER //-- 3. 创建分批处理不锁表的存储过程DROP PROCEDURE IF EXISTS BatchUpdateDiscuzLinks //CREATE PROCEDURE BatchUpdateDiscuzLinks()BEGIN
    -- 变量定义
    DECLARE v_min_pid INT;    DECLARE v_max_pid INT;    DECLARE v_current_pid INT;    DECLARE v_batch_size INT DEFAULT 1000; -- ★这里可以修改每次处理的条数,建议 500-1000
    DECLARE v_affected_rows INT;    
    -- 定义你的新老域名 (请在此处修改)
    DECLARE v_old_url VARCHAR(255) DEFAULT 'http://A旧域名.com/data/attachment/';    DECLARE v_new_url VARCHAR(255) DEFAULT 'http://B新域名.com/data/attachment/';    -- 获取帖子的最小和最大ID,确定处理边界
    SELECT MIN(pid), MAX(pid) INTO v_min_pid, v_max_pid FROM pre_forum_post;
    
    IF v_min_pid IS NOT NULL THEN
        SET v_current_pid = v_min_pid;        
        -- 开始循环遍历
        WHILE v_current_pid <= v_max_pid DO            
            -- 执行核心替换逻辑:通过主键区间限制,强制使用行级锁,绝不锁表!
            UPDATE pre_forum_post 
            SET message = REPLACE(message, v_old_url, v_new_url) 
            WHERE pid >= v_current_pid 
              AND pid < v_current_pid + v_batch_size              AND message LIKE CONCAT('%', v_old_url, '%'); -- 只有包含旧链接的帖子才执行替换
            
            -- 获取本次实际替换影响的行数
            SET v_affected_rows = ROW_COUNT();            
            -- 写入日志 (只在有实际替换发生,或者每隔一定区间时记录,避免日志爆满)
            IF v_affected_rows > 0 THEN
                INSERT INTO pre_migration_log (process_type, start_id, end_id, affected_rows, status_msg)                VALUES ('POST_URL_REPLACE', v_current_pid, v_current_pid + v_batch_size - 1, v_affected_rows, 'Success');            END IF;            
            -- 游标向前推进
            SET v_current_pid = v_current_pid + v_batch_size;            
            -- ★关键:每次批处理后休眠 0.1 秒,释放 CPU 和 IO 资源给论坛正常用户访问
            DO SLEEP(0.1);            
        END WHILE;        
        -- 循环结束,写入一条最终完成记录
        INSERT INTO pre_migration_log (process_type, start_id, end_id, affected_rows, status_msg)        VALUES ('POST_URL_REPLACE', v_min_pid, v_max_pid, 0, 'ALL_COMPLETED');        
    END IF;END //-- 恢复默认结束符DELIMITER ;-- ==========================================================-- 4. 立即一键触发执行! (如果是大表,点击运行后请耐心等待)-- ==========================================================CALL BatchUpdateDiscuzLinks();

如何查看执行情况与日志?

在上述代码执行期间(如果你使用的是 Navicat,它会显示“正在运行中”),你可以新开一个查询窗口,执行以下语句实时监控进度:

SQL
-- 查看最新的 50 条替换日志SELECT * FROM pre_migration_log ORDER BY id DESC LIMIT 50;-- 统计已经成功替换的帖子总数SELECT SUM(affected_rows) AS total_replaced_posts FROM pre_migration_log;

这套方案为什么是“最优解”?

  1. 极度安全(Idempotent 幂等性): 因为使用了 message LIKE '%旧URL%' 作为前提条件,这个脚本哪怕中途因为网络原因断开,你再次运行它也是安全的,绝不会把新链接又重复替换坏。

  2. 业务零感知(Zero Downtime): 行级锁 + DO SLEEP(0.1) 的组合,就像是在高速公路上一点点修补沥青,而不像全表 UPDATE 那样直接把高速公路封死。用户发帖、浏览毫无卡顿感。

  3. 高度掌控(Observability): pre_migration_log 表让你对到底改了哪个 ID 段的数据、改了多少条,了如指掌。

这样,即使你的论坛 pre_forum_post 里面有几千万条数据,高达数十GB,这个脚本也能在后台安静、平滑地帮你把所有历史附件的链接全部迁移到对象存储的域名上!

如果对象储存的信息我已经拿到并写入了数据库,是不是就可以通过后台php页面执行这个最优解的sql执行语句?另外,文件迁移建议是使用PHP文件执行还是人工迁移,那个更稳妥?

第一部分:关于通过后台 PHP 页面执行这个 SQL

结论:可以,但绝对不建议直接在一个普通的 PHP 页面请求中调用这个存储过程。

为什么?(坑在哪里):
前面我们写的存储过程,虽然在 MySQL 层面做到了分批、不锁表,但如果你通过网页(HTTP 请求)触发一个 PHP 脚本去执行 mysqli_query("CALL BatchUpdateDiscuzLinks()"),会面临一个致命问题:PHP 和 Web 服务器(Nginx/Apache)的超时限制。

  • 如果你的帖子表很大,整个存储过程可能需要跑 5 分钟甚至 30 分钟。

  • 而 PHP 默认的 max_execution_time 通常是 30 秒或 60 秒。Nginx 也有 fastcgi_read_timeout

  • 时间一到,页面会直接报 502 Bad Gateway504 Gateway Timeout。虽然底层的 MySQL 存储过程可能还在继续跑,但你的前端页面已经断开了,你无法知道执行结果,很容易引起运维恐慌。

正确的 PHP 执行姿势:
如果你非要用 PHP 来做(比如你想集成到 Discuz 插件或后台应用中),行业标准的做法是放弃 MySQL 存储过程,改用 PHP + AJAX/Meta Refresh 来做分批循环。

也就是:

  1. 页面加载,PHP 查出 MIN(pid)

  2. PHP 执行一次 UPDATE ... WHERE pid >= 1 AND pid < 1000,然后页面输出一条日志:“已处理 1-1000 条”。

  3. 页面通过 JavaScript 或 <meta http-equiv="refresh"> 自动刷新,并将下一批的起始 ID(1000)传给 PHP。

  4. 如此循环,直到处理完毕。
    (Discuz 官方后台的“数据库升级”和“更新缓存”功能,底层全都是这种 AJAX 分批请求的设计,就是为了绕过 PHP 超时。)

如果用存储过程,最稳妥的调用方式:
直接登录服务器,用命令行执行,或者用 Navicat 等数据库管理工具执行。


第二部分:文件迁移,用 PHP 还是人工(专用工具)?

结论:强烈建议“人工”使用【对象存储官方的同步工具】,绝对不要用 PHP 脚本去跑文件迁移!

在处理 GB 乃至 TB 级别的附件物理文件转移时,PHP 脚本显得极其脆弱。

为什么不要用 PHP 跑物理文件迁移?

  1. 单线程且极慢: PHP 默认是单线程的,一张张图片上传到对象存储,几十万个附件能传到地老天荒。

  2. 内存溢出(OOM): 读取大文件(如几十MB的压缩包)容易撑爆 PHP 内存(memory_limit)。

  3. 网络抖动灾难: 传输过程中一旦发生网络闪断,PHP 脚本中断,你很难知道哪些传成功了,哪些失败了,没有断点续传功能。

行业标准的“稳妥”迁移方案:使用官方专用迁移工具

所有的主流对象存储厂商,都提供了企业级的命令行工具(CLI)或桌面客户端。比如:

  • 阿里云 OSS: 使用 ossutil 工具。

  • 腾讯云 COS: 使用 coscli 或桌面版 COSBrowser

  • 通用开源神器: Rclone (强烈推荐,支持国内外几乎所有对象存储)。

这些专业工具的碾压级优势:

  1. 多线程并发: 可以同时开启 20 个甚至 50 个线程上传,榨干你的服务器带宽,速度是 PHP 的几十倍。

  2. 断点续传: 中途断网了、服务器重启了?没关系,重新运行命令,它会自动跳过已上传的文件,接着传剩下的。

  3. MD5 完整性校验: 传完后,工具会自动对比 A服务器和 B对象存储 文件的 MD5 值,确保文件没有损坏或漏传。

  4. 增量同步: 命令跑完后,你可以再跑一次,它只会把这两次期间论坛新产生的增量附件传过去。


🏆 资深工程师的终极迁移工作流(Best Practice)

按照以下 4 步走,保证你的迁移如丝般顺滑,业务零中断:

Step 1:准备阶段(工具同步数据)
在 A 服务器上安装对象存储的同步工具(如 ossutil),执行同步命令,将 /data/attachment/ 目录挂机全量同步到 B 对象存储。
(此时论坛正常运行,用户还在产生新附件存入 A 服务器)

Step 2:追平增量数据
选一个夜深人静的时刻(如凌晨 3 点)。再去 A 服务器跑一次刚才的同步命令。因为绝大多数文件已经传完了,这次“增量同步”可能只需要 1 分钟就把白天新发的文件同步过去了。

Step 3:切换写入(配置后台)
立即登录 Discuz 后台 -> 全局 -> 上传设置 -> 远程附件,填好 B 对象存储的信息,开启并保存。
(从这一秒起,新发的附件已经直接去 B 了)

Step 4:修改历史链接(执行 SQL)
打开 Navicat 或数据库工具,执行我之前写给你的那套“分批、不锁表”的 SQL 存储过程(或替换语句)。
(此时历史帖子的图片全部指向 B 域名)

最后更新一下 Discuz 缓存,收工!整个过程用户基本毫无感知,数据 100% 完整不丢失。

欢迎阅读本文,希望本文对您有所帮助!

本文链接:https://2kk8.com/?id=1323

版权声明:本文为原创文章,版权归 user666 所有,欢迎分享本文,转载请保留出处!

内页底部广告(PC版),后台可以自由更改

9KKD.com

9KKD.com

这里的内容可以随意更改,在后台-主题配置中设置。

百度推荐获取地址:http://tuijian.baidu.com/,百度推荐可能会有一些未知的问题,使用中有任何问题请直接联系百度官方客服!
评论框上方广告(PC版),后台可以自由更改

评论(0) 赞助本站

9KKD惠万家

发表评论:


【顶】 【踩】 【好】 【懵】 【赞】 【表情】

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

推荐阅读
05月06日

黄仁勋与英伟达NVIDIA

发布 : | 分类 : 创享学习 | 评论 : 0人 | 浏览 : 258次

英伟达(NVIDIA)最新财报的核心数据,以及创始人兼CEO黄仁勋的个人详细资料。截至当前(2026年5月),英伟达刚刚发布了其2026财年...

02月26日

页面烟花效果代码

发布 : | 分类 : 创享学习 | 评论 : 0人 | 浏览 : 805次

yanhua.js 七彩效果/**  * 烟花特效优化版 2KK8.com 2026-02-26  * 使用方法,页面插入: <script src="yanhua.js"></script>  */ (function() {     // requestAnimationFrame 兼容处理     var requestAnimationFrame = window.requestAnimationFr...

02月09日

寒假开始,规划开始 2026-02-09

发布 : | 分类 : 创享学习 | 评论 : 0人 | 浏览 : 877次

第一部分:如何与孩子沟通——给一个无法拒绝的“提案”沟通时机:找一个大家很放松的时间,比如周末下午,“聊聊寒假规划”开头。沟通核心逻辑:不谈“学习”,谈“赢的游戏”。不谈“工具”,谈“赢的装备”。...