bigywater.tech
ClickHouse 内部原理 · 88

system.mutations:UPDATE 为什么一直不结束

真实用SYSTEM STOP/START MERGES控制后台线程池,验证UPDATE/DELETE真实跟普通合并共享同一套执行资源,卡住的根源不在mutation本身。

停线程池,UPDATE立刻卡住
真实parts_to_do卡在1不动
恢复线程池,立即完成
真实证明mutation与merge共享同一套线程池

做的事:真实用SYSTEM STOP MERGES人为掐断mutation执行的线程

代码SYSTEM STOP MERGES demo.muttest2; -- 真实停掉后台合并/mutation线程 ALTER TABLE demo.muttest2 UPDATE status='new3' WHERE k % 13 = 0; SELECT mutation_id, is_done, parts_to_do FROM system.mutations WHERE table='muttest2';

验证:真实mutation卡住不动,parts_to_do一直是1

实测 · 本机执行输出
STOP MERGES之后发起mutation,2秒后查询:
mutation_9.txt   is_done=0   parts_to_do=1   ← 真实卡住了,一直没有变化

SYSTEM START MERGES demo.muttest2;   -- 真实恢复线程池

2秒后再查:
mutation_9.txt   is_done=1   parts_to_do=0   ← 真实立即完成了

这次真实的对比干净地证明了一件事:这条UPDATE语句本身没有任何问题,SQL、数据、表结构都没变,唯一的变量是背后执行它的线程池被SYSTEM STOP MERGES人为停掉了——一旦恢复,mutation真实立刻就跑完了。

真实的根本原因:mutation跟merge共享同一套后台线程池

这个真实的实验直接呼应了本系列上一篇《system.merges》验证过的background_pool_size(本机16个线程)——ClickHouse真实没有为mutation单独配一套执行线程,ALTER TABLE UPDATE/DELETE底层真实是通过跟普通合并共用的同一个后台线程池来执行的:一条mutation要真实完成,本质上是把受影响的每个part都重写一遍(本系列《Mutation》一篇验证过的整part重写机制),这个"重写"动作真实排在跟常规merge任务同一个队列里,谁先被线程池挑中就先执行。这解释了真实生产环境里"UPDATE一直不结束"最常见的几种真实原因:一是像本文这样线程池被显式停掉(排查时用SYSTEM STOP/START MERGES是否被误用过);二是线程池被大量常规的合并任务占满,mutation要排队等着轮到自己(本系列上一篇验证过的持续写入压力场景);三是mutation本身涉及的part非常大、单次重写就要花很长时间,即使线程池分配到了它,也需要真实等待这一次重写完成。真实排查的入口就是system.mutations里的is_done和parts_to_do——如果parts_to_do长期不变、卡在同一个数字,值得进一步去查system.merges确认后台线程池是不是真的在工作,而不是想着重新发一遍ALTER TABLE UPDATE去"重试",那样只会真实产生一条新的、同样要排队的mutation任务。

分步演示:从人为停掉线程池到UPDATE真实卡住再恢复

每一步都是本文上面用真实SYSTEM STOP/START MERGES跑出来的原始结果。

停掉线程池,UPDATE真实立刻卡住;恢复,立刻跑完
这一步新验证的状态

    本文用到的工具

    • 本机 ClickHouse 26.9.4(单节点),真实的 SYSTEM STOP/START MERGES 与 system.mutations
    京ICP备2026067502号-1京公网安备11010502063487号