批量更新是对相关表的大量行进行更改的关键过程。在SQL历史上,典型的实现是带有子查询或JOIN的UPDATE。问题在于:任何没有控制执行顺序的批量更新操作都会阻塞多行,导致锁升级,并可能在多个更新时造成死锁。
解决方案:
代码示例(PostgreSQL):
UPDATE Orders o SET status = 'archived' FROM Customers c WHERE o.customer_id = c.id AND c.closed = TRUE AND o.status != 'archived';
或者批量:
WITH upd AS ( SELECT o.id FROM Orders o JOIN Customers c ON o.customer_id = c.id WHERE c.closed = TRUE AND o.status != 'archived' LIMIT 10000 ) UPDATE Orders SET status = 'archived' WHERE id IN (SELECT id FROM upd);
关键特性:
如果同时启动更新相似表而没有划分范围或交叉过滤会发生什么?
可能会出现死锁:进程阻塞同一行,互相等待。为避免这种情况 — 批处理必须不重叠或严格按顺序启动。
在进行大规模状态更改时,JOIN和子查询的UPDATE有什么区别?
如果有合适的索引,主要区别仅在于可读性和某些情况下具体数据库的性能。JOIN通常更快,因为它允许优化器制定更好的计划。
何时使用TRUNCATE/DELETE而不是UPDATE?
如果业务逻辑允许 — 例如,需要物理删除归档记录或清空表,而不仅仅是更改状态标志。但对于批量更新状态 — 仅使用UPDATE。
在一家大型电商中,同时启动多个UPDATE以更改订单和客户状态,而没有按时间段划分。结果:相互阻塞,多次需要强制回滚,未写入的数据被回滚。
优点:
缺点:
大选择集被拆分为批次,严格按顺序启动,仅处理通过过滤器所需的行。
优点:
缺点: