Postgres 是不是会在更新时重写整行?

Posted

技术标签:

【中文标题】Postgres 是不是会在更新时重写整行?【英文标题】:Does Postgres rewrite entire row on update?Postgres 是否会在更新时重写整行? 【发布时间】:2014-03-28 01:47:34 【问题描述】:

我们在 Windows 2008 Server 上运行 Postgres 9.0。有一个大表包含一个bytea列,用于存储每行0-5MB范围内的二进制数据:

CREATE TABLE files
(
  file_id serial NOT NULL,
  data bytea NOT NULL,
  on_disk boolean,
  CONSTRAINT files_pkey PRIMARY KEY (file_id)
)

最近我们一直在更新每一行的 on_disk 字段(不涉及数据字段)。我们认为这已经占用了我们临时表空间(或其他东西)中的空间,原因有两个:

1) 我们开始在系统的其他随机部分运行大型查询时收到此错误:

ERROR: 53100: could not write block 92271 of temporary file

2) 我们的可用空间在一周内从约 7GB 下降到 1.5GB,这是不寻常的。

谁能确认:

a) 在 postgres 中更新一行是否会导致它重写整个行(包括大型二进制数据)而不释放旧空间?这可以解释我们的症状

b) 它是否在更改期间写入其他一些临时表空间,这也占用了空间? (我们可以强制释放临时空间吗?)

c) 有没有一种方法可以对这个表执行较小的布尔字段更新,而无需每次都重写行(& 占用磁盘空间)?

d) 我们可以强制 postgres 定期释放已用空间而不重写整个表吗? (我们已知的释放空间的方法涉及到我们没有空间的表重写)

P.S.:是的,我们正在将我们的服务器迁移到具有更大存储空间的主机上……这可能需要 1-2 个月的时间。

【问题讨论】:

@paqogomez PostgreSQL 9.0 在 Windows 上。 老实说,对于一个问题来说,这些问题太多了。政策是针对每个问题提出一个明确的问题。 large queries 也可能会占用临时表空间...也许? 【参考方案1】:

从您的问题中选择 c)

有没有办法我们可以对此执行较小的布尔字段更新 每次都没有重写行(&咀嚼磁盘空间)的表?

作为@Craig already explained,“TOAST-able”且大于某个阈值的列被离线存储在每个表的专用 TOAST 表中(单独的“关系分支”,磁盘上的单独文件)。因此,如果列本身未更改,则 5 MB bytea 列将在更新中基本保持不变。 The manual:

在 UPDATE 操作期间,未更改字段的值通常是 按原样保存;因此会导致更新具有线外值的行 如果没有任何异常值发生变化,则没有 TOAST 成本。

我的大胆强调。 主关系分支中的行仍然被复制,并且在更新时死行留在后面(无论是否实际更改了任何值)。对于较大的行大小,以下解决方案可能会有所帮助:

为经常更改的标志创建一个小的单独的 1:1 表。只是主键(同时=外键)和经常更改的标志。这将使更新更快并保留磁盘空间 - 用于需要连接两个表的查询的初始额外开销和一些成本(其他查询实际上变得更快)。更多关于表行的磁盘空间要求:

Making sense of Postgres row sizes

【讨论】:

【参考方案2】:

至少在 9.3 中,如果 TOAST 表中存储的字段异常存储,PostgreSQL 不会重写它们。不知道9.0是不是这样。

您可以使用\d+ tablename 来查看列所使用的存储空间; storage 列显示使用的模式。如果单个元组足够小(例如:extended 存储列中也是如此。

请参阅 the documentation for TOASTALTER TABLE ... SET STORAGE

临时文件存储在temp_tablespaces。默认情况下它是空的,在这种情况下它会回退到default_tablespace,如果为空,它又会回退到pg_default 表空间。

表/索引中的空间应由 autovacuum 自动释放以供重复使用。确保您的 autovacuum 守护程序运行得足够频繁,并且没有设置太多的 cost_delay。自 9.0 以来,Autovacuum 得到了显着改进。

如果您想将空间释放回操作系统或用于其他表,您需要VACUUM FULL 或use an external tool like pg_repack 以较少干扰的方式执行此操作。

【讨论】:

有用的答案,谢谢。 pg_repack 是信誉良好的产品吗?我犹豫要不要在生产环境中运行它。 我不使用它,也没有理由详细评估它,所以我不能直接评论。我知道它确实看到了重要的生产用途。 可能不是在最初提出问题的时候,但在这一点上,pg_repack 是一个有声望的项目,我们经常在 OmniTI 的各种数据库的生产中使用它。

以上是关于Postgres 是不是会在更新时重写整行?的主要内容,如果未能解决你的问题,请参考以下文章

Postgres 更新语句

Postgres SQL 触发器在 TableB 上插入或更新后使用新值更新 TableA.column

如何确定 postgres 视图是不是可更新

identifierForVendor 是不是会在应用更新时发生变化?

使用 JDBC 连接到 postgres 时是不是可以指定架构?

使用 JDBC 连接到 postgres 时是不是可以指定模式?