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 TOAST
和 ALTER 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 SQL 触发器在 TableB 上插入或更新后使用新值更新 TableA.column
identifierForVendor 是不是会在应用更新时发生变化?