Postgres - 没有实际更新,它有副作用吗?

Postgres - No actual UPDATE, has it side-effects?

我有一个 table,它包含大约 5000 万行。我想执行一个简单的更新查询:

UPDATE the_table SET flag = true;

对于其中 99% 的行,标志已设置为 true。因此只有 1% 的行必须更改。

我的问题是:Postgres 是否足够聪明,知道这一点?或者 Postgres 是否会更改这 99% 的行,这将导致典型的进程,例如 WAL、自动真空、重新索引、同步到从站,...对于整个 table,而不仅仅是这些1% 行。

换句话说,下面的查询是不是更安全的方法?

UPDATE the_table SET flag = true WHERE flag = false;

不,Postgres 不会检查您是否更新到相同的值。

邮件列表中时不时地讨论这个问题,但共识是支票太贵了,让所有用户为只有少数用户(通常是用户)支付的东西没有意义糟糕的混淆层 - 又名 "ORM") 需要。

第二种解决方案是进行更新的最安全和最佳方法。

Postgres 不会区分 flag=trueflag=false (或 flag 是null,就此而言)执行更新时。但是,这两个语句的结果并不完全等同;或者,至少,它们不是一般的。

有两个主要的副作用:

  1. 第一个查询(无 where 子句)将扫描并处理 table 中的所有行。在第二种情况下,如果有适当的索引,它可能只会去处理几行。 "what's on the table" 的最终结果(除了触发器的影响)将是相同的。实现此最终结果所花费的时间可能会有很大不同。

  2. 如果 table(或视图)有一个 trigger that fires "ON UPDATE" and "FOR EVERY ROW" (see CREATE TRIGGER),将在您的第一个查询中为 table 上的每一行调用触发器函数,并且仅对于行 WHEREwhere condition 在第二个为真。同样有两个区别:(1) 时间和 (2) 触发器的动作。例如,如果触发器要更新 "lastmod" 列,它会在第一种情况下为每一行更新它 [这可能不是您想要的]。

...和可能的第三个:

  1. 在足够并发的情况下:第一个查询将阻塞 table 中的所有行;或者语句可能被阻止更新某些行,因为另一个事务同时是它们。因此,要么等待时间长,要么死锁。更新的行数越多,对争用产生某些影响的可能性就越大...(或死锁等)

最常用的更新方式是使用带有 WHERE 子句的查询。一些非常特殊的情况可能会推荐第一个(例如,您 实际上想要 更新一个 "lastmod" 列,即使该行中的其余值没有更新)。

"By default" 使用 WHERE 进行查询。某些数据库(即:MySQL 和 safe update)甚至可能不允许您在没有 WHERE 子句的情况下执行 UPDATE(或 DELETE)。