update慢主因是全表扫描或索引失效,需用explain确认索引命中;避免where中函数操作、子查询及null值;优先用join或values列表代替子查询;注意事务设置与超时配置。

UPDATE 语句慢得离谱?先看执行计划有没有走索引
没加 WHERE 条件的全表扫描,或者 WHERE 字段没索引,是批量更新变慢最常见原因。MySQL/PostgreSQL 都会默默全扫一遍再改,哪怕只改 10 行,也可能锁住上万行。
- 用
EXPLAIN UPDATE ...(MySQL)或EXPLAIN ANALYZE UPDATE ...(PostgreSQL)确认是否命中索引 -
WHERE条件里别对字段做函数操作,比如WHERE YEAR(created_at) = 2024会让索引失效,改成WHERE created_at >= '2024-01-01' AND created_at - 复合索引要注意字段顺序:如果
WHERE a = ? AND b = ?,索引应为(a, b),反过来就可能用不上
一次更新 10 万行,为什么锁表又超时?
大事务 = 长时间持有行锁/表锁 + binlog 增长 + 主从延迟。尤其在 MySQL 的 REPEATABLE READ 隔离级别下,大 UPDATE 可能触发间隙锁,连不相关的行都锁住。
- 拆成小批次更新,比如每次 1000–5000 行,用
WHERE id BETWEEN ? AND ?或WHERE id > ? ORDER BY id LIMIT 5000 - 显式加
FOR UPDATE不必要,普通UPDATE本身就会加行锁;但若逻辑依赖 SELECT 再 UPDATE,记得用SELECT ... FOR UPDATE避免并发覆盖 - 避免在事务里混用 DDL(如 ALTER TABLE),DDL 会锁整个表,和你的 UPDATE 死锁概率陡增
用 JOIN 更新多张表,MySQL 和 PostgreSQL 写法完全不同
MySQL 支持 UPDATE t1 JOIN t2 ON ... SET t1.x = t2.y,PostgreSQL 必须写成 UPDATE t1 SET x = t2.y FROM t2 WHERE t1.id = t2.t1_id。写错直接报语法错误,不是逻辑错。
Zen Cart 是一款高速、稳定、功能强劲的免费开源网店系统,基于PHP语言开发的开源电子商务解决方案,用于建立专业的网上商店,支持多语言、多货币、多插件、搜索引擎优化、批量更新,是最安全的网店系统之一,特别适合外贸网站建设。
- MySQL 多表 UPDATE 中,
SET只能赋值给目标表字段,不能写t2.y = ... - PostgreSQL 的
FROM子句里,如果t2有重复关联行,UPDATE 会执行多次——结果取决于哪一行最后生效,行为不确定,务必加DISTINCT ON或聚合过滤 - 两者都不支持在 JOIN UPDATE 中用子查询当右值(比如
SET x = (SELECT ...)),会报错或性能极差,提前把子查询结果落临时表更稳
WHERE 条件含子查询?小心 N+1 和全表扫描
UPDATE t SET status = 'done' WHERE id IN (SELECT id FROM temp_list) 看似简洁,实际在 MySQL 5.6 之前会转成嵌套循环,每行都查一次子查询;PostgreSQL 虽优化较好,但子查询无索引照样慢。
- 把子查询结果先插入临时表,并在该表的关联字段上建索引,再用 JOIN 方式更新
- 避免
WHERE col IN (SELECT ...)中的SELECT返回 NULL:NULL 会导致整行被跳过(SQL 标准中x IN (NULL)永远为 UNKNOWN) - 如果子查询来自应用层,优先考虑用
VALUES列表代替,比如WHERE id IN (1, 5, 8, 12)—— 这个比子查询快一个数量级,且可控
批量 UPDATE 最容易被忽略的,其实是 autocommit 开关和连接超时设置。应用代码里没关自动提交,每条 UPDATE 都单独事务,速度慢还容易被打断;数据库侧的 wait_timeout 或 statement_timeout 设得太短,大批次还没跑完就断连了。这些不在 SQL 里,但决定你能不能跑通。









