更新具有相同值的行实际上会更新该行吗?

One*_*ofo 38 postgresql performance update postgresql-performance

我有一个与性能相关的问题。假设我有一个名为 Michael 的用户。进行以下查询:

UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
Run Code Online (Sandbox Code Playgroud)

查询是否会实际执行更新,即使它被更新为相同的值?如果是这样,我该如何防止它发生?

Erw*_*ter 46

由于Postgres的MVCC 模型,并且根据 SQL 的规则,对于子句中没有排除的每一行,都会UPDATE写入一个新的行版本。WHERE

确实或多或少地直接或间接地对性能产生了重大影响。“空更新”的每行成本与任何其他更新相同。它们会像任何其他更新一样触发触发器(如果存在),它们必须被WAL 记录,并且它们会产生使表膨胀的死行,并VACUUM像任何其他更新一样导致更多的工作供以后使用。

索引条目和更改任何相关列的TOAST可以保持不变,但对于任何更新的行都是如此。有关的:

排除此类空更新几乎总是一个好主意(当有可能发生时)。您没有在问题中提供表定义。我们必须假设first_name可以为 NULL(对于“名字”来说这并不奇怪),因此查询必须使用NULL 安全比较

UPDATE users
SET    first_name = 'Michael'
WHERE  id = 123
AND    first_name IS DISTINCT FROM 'Michael';
Run Code Online (Sandbox Code Playgroud)

如果first_name IS NULL在更新之前,使用 just 的测试first_name <> 'Michael'将评估为 NULL,因此从更新中排除该行。偷偷摸摸的错误。如果定义NOT NULL列,请使用简单的相等性检查,不过这样会便宜一些。

有关的:

  • @jberryman:我实际上*不知道*该项目如此发展的原因。那是很久以前建立的。但是我*假设*检查每一行是否相等并且为未更改的行使用单独的代码路径将是不必要的昂贵。事务 ID 的处理会更复杂——“回滚”的特殊大小写、快照处理、锁管理、WAL,还有什么不是…… (2认同)

Thr*_*onk 5

ORM 就像 Ruby on Rail 提供的延迟执行,它将记录标记为已更改(或未更改),然后在需要或调用时将更改提交到数据库。

PostgreSQL 是一个数据库而不是 ORM。如果花时间检查新值是否与查询中的更新值相同,则会降低性能。

因此,无论它是否与新值相同,它都会更新该值。

如果您希望防止这种情况发生,您可以使用 Max Vernon 在他的回答中建议的代码。