由于PostgreSQL MVCC,UPDATE 实际上很像DELETE 加上INSERT。除了烤值的显着例外 - 请参阅:
(仅堆元组的细微差别 - DELETE + INSERT 启动一个新的 HOT 链 - 但这与手头的情况无关。)
确切地说,“已删除”行对于在提交删除后开始的任何事务都是不可见的,并且稍后会被清理。因此,在数据库方面,包括索引操作在内,这两条语句实际上没有区别。 (有例外情况,请继续阅读。)它会稍微增加网络流量(取决于您的数据)并且需要进行一些解析。
在@araqnid 的输入之后,我进一步研究了 HOT 更新并进行了一些测试。就 HOT 更新而言,实际上不会更改值的列的更新没有任何区别。我的回答成立。请参阅下面的详细信息。
这也适用于 toasted 属性,因为除非值实际更改,否则这些属性也不会被触及。
但是,如果您使用每列触发器(在 pg 9.0 中引入),这可能会产生不希望的副作用!
我引用the manual on triggers:
...诸如UPDATE ... SET x = x ... 之类的命令将触发触发器
列x,即使列的值没有改变。
我的大胆强调。
抽象层是为了方便。它们对于不了解 SQL 的开发人员或者如果应用程序需要在不同的 RDBMS 之间移植时很有用。不利的一面是,它们会影响性能并引入额外的故障点。我尽可能避免使用它们。
HOT(仅堆元组)更新
仅堆元组是随 Postgres 8.3 引入的,对 8.3.4 和 8.4.9 进行了重要改进。
The release notes for Postgres 8.3:
UPDATEs 和 DELETEs 留下死元组,失败的 INSERTs 也是如此。
以前只有VACUUM 可以回收死元组占用的空间。和
HOT死元组空间可以在执行时自动回收
INSERT 或 UPDATE 如果没有对索引列进行更改。这
允许更一致的性能。此外,HOT 避免添加
重复的索引条目。
强调我的。并且“无更改”包括使用与它们已有的相同值更新列的情况。我实际测试过,我不确定。
最终,广泛的README.HOT in the source code 证实了这一点。
Toasted 列也不妨碍 HOT 更新。 HOT 更新的元组只是链接到关系的 toast 分支中相同的、未更改的元组。热更新甚至适用于目标列表中的烤值(实际更改与否)。如果 toast 的值发生变化,显然需要写入 toast 关系分支。我也测试了所有这些。
不要相信我的话,你自己看看。 Postgres 提供了几个functions to check statistics。运行您的 UPDATE 有和没有所有列,并检查它是否有任何区别。
-- Number of rows HOT-updated in table:
SELECT pg_stat_get_tuples_hot_updated('table_name'::regclass::oid)
-- Number of rows HOT-updated in table, in the current transaction:
SELECT pg_stat_get_xact_tuples_hot_updated('table_name'::regclass::oid)
或使用pgAdmin。选择您的表格并检查主窗口中的“统计”选项卡。
请注意,只有在主关系分支的同一页面上有新元组版本的空间时,才可能进行 HOT 更新。强制该条件的一种简单方法是使用仅包含几行的小表进行测试。页面大小通常为 8k,因此页面上必须有可用空间。