表具有以下结构:
- 援助
- b:大jsonb
- c: 大 jsonb
- d:时间戳
查看两周内的统计数据,看到许多更新:
- 90k 请求仅更新
d
字段(总时间:从应用程序测量的 25 分钟) - 90k 请求更新“large jsonb”字段(总时间:从应用程序测量的 6 小时 30 分)
d
由于 Postgres 遵循 MVCC 模式,在更新时重写行,因此将表结构更改为单独的表是否有趣?
表具有以下结构:
查看两周内的统计数据,看到许多更新:
d
字段(总时间:从应用程序测量的 25 分钟)d
由于 Postgres 遵循 MVCC 模式,在更新时重写行,因此将表结构更改为单独的表是否有趣?
不,那没有必要。大的 JSON 值似乎存储在 TOAST 表中。然后更新
d
只需向主表写入新行,但 TOAST 值保持不变。如果 JSON 值足够小,可以存储在主表中,则修改的
d
成本会高得多,因为它必须再次写入包含 JSON 的整行。那么考虑这样的分离可能是有意义的。正如Laurenz所建议的那样,在TOAST表中存储的列值和在 TOAST 表中未触及的列值
UPDATE
可以保持原样,从而节省工作量和存储空间。(主关系的新旧行版本指向相同的 TOAST 条目。)但这是有细则的。
你还在敬酒吗?
行大小必须超过
TOAST_TUPLE_THRESHOLD
(通常为 2 kb)才能考虑。某些列可能已经被压缩。然后,TOAST 机制将尝试压缩更多列,直到大小低于TOAST_TUPLE_TARGET
(通常相同的 2 kb)。只有当它无法实现这一点时,它才会开始将数据移动到 TOAST 表,一次一列。在我的快速测试中,默认压缩算法将数据
pglz
压缩jsonb
为 3 到 4 倍左右。(根据内容而变化。)因此,在 TOAST 任何内容之前,行的原始大小必须超过 7 kb 左右。然后可能只有两个“大”列之一。这可能会导致主关系中的中等大小元组最多 2 kb,这让我们回到了您最初的考虑。仔细查看
jsonb
值的压缩(!)大小以及主关系(最小值、最大值、平均值、平均值)中的实际元组大小,以做出明智的决定。这是一篇包含有用查询的博客文章:
“不变”
关于:
通常,更新实际上仅更改一列或另一列,或者更新一列或另一列而不进行实际更改。如果列“未更改”,则 TOAST 列值保持不变。准确地说:如果该列未在
UPDATE
. 如果您用未更改的值覆盖列,则视为“已更改”。Postgres 不会验证该值是否实际更改并写入新的行版本,包括 TOAST。通过智能查询设计避免此类“空”更新。看:压缩算法
lz4
如果您所披露的是表中发生的所有情况,请考虑非默认 LZ4 压缩算法。(从Postgres 14开始可用。)它速度更快,但压缩量更少。(在我的数据快速测试中,结果大小大约增加了 15%
jsonb
。)以下是博客文章,其中与首次发布时进行了详尽的比较:看:
总之,使用适当的压缩算法,然后使用智能查询,然后收集数据的有效统计信息,然后决定分解一列或另一列是否有意义。必须有明显的好处来证明开销的合理性。