我有一个与性能有关的问题。假设我有一个名字为Michael的用户。进行以下查询:
UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
即使将查询更新为相同的值,查询也会实际执行该更新吗?如果是这样,我如何防止它发生?
我有一个与性能有关的问题。假设我有一个名字为Michael的用户。进行以下查询:
UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
即使将查询更新为相同的值,查询也会实际执行该更新吗?如果是这样,我如何防止它发生?
Answers:
由于Postgres 的MVCC模型,并且根据SQL的规则,UPDATE
a会为子句中未排除的每一行写一个新的行版本WHERE
。
这确实对性能产生了或多或少的直接或间接影响。“空更新”每行的成本与任何其他更新相同。它们像其他任何更新一样触发触发器(如果存在),必须对其进行WAL记录,并且它们会产生死行,使表膨胀,并VACUUM
像其他任何更新一样导致以后进行更多工作。
索引条目和未更改任何涉及的列的TOASTed列可以保持不变,但是对于任何更新的行都是如此。有关:
排除这样的空更新几乎总是一个好主意(如果确实有可能发生)。您没有在问题中提供表定义(这总是一个好主意)。我们必须假设first_name
可以为NULL(对于“名字”来说并不奇怪),因此查询必须使用NULL安全比较:
UPDATE users
SET first_name = 'Michael'
WHERE id = 123
AND first_name IS DISTINCT FROM 'Michael';
如果first_name IS NULL
在更新之前,带有just的测试first_name <> 'Michael'
将评估为NULL,因此从更新中排除该行。鬼error的错误。如果定义NOT NULL
了column ,那么请使用简单的相等性检查,因为这样做便宜一些。
有关:
Indexes entries and TOASTed columns where none of the involved columns are changed can stay the same
但是,是否不必更新它们以指向该行的新位置?
rollback
,快照处理,锁管理,WAL,等等……
您可以简单地添加以下where
子句:
UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
AND (first_name <> 'Michael' OR first_name IS NULL);
如果first_name
定义为NOT NULL
,则OR first_name IS NULL
可以删除零件。
条件:
(first_name <> 'Michael' OR first_name IS NULL)
也可以写得更优雅一些(在欧文的答案中):
first_name IS DISTINCT FROM 'Michael'
NULL
@erwin 的评论
从数据库的角度
您问题的答案是“是”。更新将进行。数据库不检查以前的值,它仅设置新值。
由于这发生在内存中(并且只会在发出提交后才写入数据文件),因此性能不会成为问题。
从ORM角度
通常,您将有一个对象代表数据库的一行(它可能比这要复杂得多,但让我们保持简单)。该对象在内存中(在应用服务器级别)进行管理,并且只有该对象的最新提交版本才会在某个特定点将其实际存储到数据库中。
这可以解释不同的行为。
现在,我们不要将货船与3D打印机进行比较。您可以使用货船发送3D打印机这一事实并不意味着它们之间可以进行任何比较。
请享用!
我希望这可以澄清一些概念。