UPDATE users u
JOIN (
  SELECT MIN(id) AS keep_id, email
  FROM users GROUP BY email HAVING COUNT(*) > 1
) d ON u.email = d.email AND u.id <> d.keep_id
SET u.status = 'dup';

写了一条带子查询的 UPDATE,想把重复记录里 id 最小的保留下来,执行时直接报 1093,语句被整条拒绝。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。

追下去是这么回事:MySQL 不允许在 UPDATE 的子查询里直接引用正在被更新的同一张表,需要加一层派生表让优化器先物化。

「MySQL 1093 错误」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。同类问题如果隔一段时间又出现,多半是某个定时任务或重启流程把改动冲掉了。

把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。改完隔一天再看一次,当场正常不代表能稳住。

测试环境和线上的差别,往往就在版本号和那几行被忽略的配置上。

处理上按这个顺序:把子查询包成派生表并起别名;派生表里只取需要的 id 列;执行前先用 SELECT 验证筛选结果条数。

确认没问题再收工,先按同样条件跑 SELECT,返回条数与 UPDATE 影响行数一致,说明没有误改。

作者 9823189