Postgres row_number() 大约每 24 小时将 table 大小加倍
Postgres row_number() doubling table size roughly every 24 hours
我有一个资产 table,里面有大约 165,000 行。但是,资产构成“集合”,每个集合可能有约 10,000 个项目,我想为其保存一个“排名”,以便用户可以看到给定资产在集合中的排名。
排名可能会发生变化(基于内部分数),因此需要定期更新(每小时几次)。
目前正在对每个集合进行此操作:
UPDATE assets a
SET rank = a2.seqnum
FROM
(SELECT a2.*,
row_number() OVER (
ORDER BY elo_rating DESC) AS seqnum
FROM assets a2
WHERE a2.collection_id = #{collection_id} ) a2
WHERE a2.id = a.id;
但是,这导致 table 的大小大约每 24 小时翻一番(即 1GB 到 2GB)。
A VACUUM FULL
解决了这个问题,但这并不是真正的解决方案。
能否调整查询以不创建太多(我假设是)临时存储?
运行 PostgreSQL 13.
每次更新都会在 Postgres 中写入一个新的行版本。因此(除了 TOASTed 列之外)更新 table 中的每一行大致使其大小翻倍。这就是你所观察到的。稍后可以清理死元组以缩小 table 的物理大小——这就是 VACUUM FULL
所做的, 非常昂贵 。参见:
或者,您可以 而不是 运行 VACUUM FULL
并将 table 保持在最小物理尺寸的两倍左右。如果你 运行 plain VACUUM
(没有 FULL
!)足够了——如果你没有长时间的 运行ning 事务阻止它——Postgres 将在free-space 映射到下一个 UPDATE
开始时可以重新使用磁盘 space,因此 保持 为最小大小的两倍。这可能比一直缩小和重新增长 table 更便宜,因为最昂贵的部分通常是物理增长 table。请务必为 table 设置激进的 autovacuum
设置。参见:
可能更好 但是,将排名分解为最小的单独 1:1 table (a.k.a."垂直分区"),因此只需“每小时几次”只写最少的行。可能包括您在查询中提到的 elo_rating
,它似乎至少经常变化(?)。
(LEFT
) JOIN
到查询中的主要 table。虽然这增加了相当大的开销,但它可能仍然(实质上)更便宜。取决于完整的图片,最重要的是 table assets
中的平均行大小和除了昂贵的更新之外的典型负载。
参见:
- Many columns vs few tables - performance wise
- UPDATE or INSERT & DELETE? Which is better for storage / performance with large text columns?
我有一个资产 table,里面有大约 165,000 行。但是,资产构成“集合”,每个集合可能有约 10,000 个项目,我想为其保存一个“排名”,以便用户可以看到给定资产在集合中的排名。
排名可能会发生变化(基于内部分数),因此需要定期更新(每小时几次)。
目前正在对每个集合进行此操作:
UPDATE assets a
SET rank = a2.seqnum
FROM
(SELECT a2.*,
row_number() OVER (
ORDER BY elo_rating DESC) AS seqnum
FROM assets a2
WHERE a2.collection_id = #{collection_id} ) a2
WHERE a2.id = a.id;
但是,这导致 table 的大小大约每 24 小时翻一番(即 1GB 到 2GB)。
A VACUUM FULL
解决了这个问题,但这并不是真正的解决方案。
能否调整查询以不创建太多(我假设是)临时存储?
运行 PostgreSQL 13.
每次更新都会在 Postgres 中写入一个新的行版本。因此(除了 TOASTed 列之外)更新 table 中的每一行大致使其大小翻倍。这就是你所观察到的。稍后可以清理死元组以缩小 table 的物理大小——这就是 VACUUM FULL
所做的, 非常昂贵 。参见:
或者,您可以 而不是 运行 VACUUM FULL
并将 table 保持在最小物理尺寸的两倍左右。如果你 运行 plain VACUUM
(没有 FULL
!)足够了——如果你没有长时间的 运行ning 事务阻止它——Postgres 将在free-space 映射到下一个 UPDATE
开始时可以重新使用磁盘 space,因此 保持 为最小大小的两倍。这可能比一直缩小和重新增长 table 更便宜,因为最昂贵的部分通常是物理增长 table。请务必为 table 设置激进的 autovacuum
设置。参见:
可能更好 但是,将排名分解为最小的单独 1:1 table (a.k.a."垂直分区"),因此只需“每小时几次”只写最少的行。可能包括您在查询中提到的 elo_rating
,它似乎至少经常变化(?)。
(LEFT
) JOIN
到查询中的主要 table。虽然这增加了相当大的开销,但它可能仍然(实质上)更便宜。取决于完整的图片,最重要的是 table assets
中的平均行大小和除了昂贵的更新之外的典型负载。
参见:
- Many columns vs few tables - performance wise
- UPDATE or INSERT & DELETE? Which is better for storage / performance with large text columns?