【问题标题】:How does postgres stores row in page, when row size exceeds available free size in page ?当行大小超过页面中可用的可用大小时,postgres 如何在页面中存储行?
【发布时间】:2018-04-03 08:44:59
【问题描述】:

我正在探索postgres的存储机制。我知道 postgres 正在使用类似页面的结构(每个大小为 8K)来存储行。一页可以包含多行。我也知道当行不能包含在给定页面中时,TOASTing 是由 postgres 完成的。

但我不确定以下情况:-

  • 当前页只剩1K空间,新建行的大小超过了1K。在那种情况下,会发生什么?是否会为该行分配新页面而旧页面将有未使用的空间?或者当另一个大小小于或等于 1K 的行被创建时,旧页面的剩余空间将被占用?

我指的是TOAST。以下段落有点不清楚:-

当要存储的行“太宽”(默认阈值为 2KB)时,TOAST 机制首先尝试压缩任何宽字段值。如果这还不足以使行小于 2KB,它会将宽字段值分解为存储在相关 TOAST 表中的块。每个原始字段值都被一个小指针替换,该指针显示在 TOAST 表中的何处可以找到此“异常”数据。 TOAST 会尝试通过这种方式将 user-table 行压缩到 2KB,但只要能达到 8KB 以下就足够了,并且可以成功存储该行。

为什么要讨论 8K 和 2K 两种尺寸?为什么 postgres 检查阈值 2K ?

提前致谢。

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    首先,我要澄清的是,“表格页面中有足够的空间”与属性是否经过 TOAST 无关。

    您引用的段落描述了 TOAST 如何尝试通过首先压缩值然后将它们“超出范围”存储在 TOAST 表中来减少超过 2KB 的表行的大小。 p>

    这个想法是减小大小,以使一行不占用表块中超过四分之一的空间。但是如果失败了,并且在 TOASTing 之后该行最终大于 2KB,那也没有问题,只要结果行适合一个 8KB 块。

    一个表行总是存储在单个表块中。如果任何现有块中没有足够的空间,则分配一个新的表块,并为现有块留下一些空白空间.此空白空间仍可用于其他较小的新行。

    表块的 8KB 限制和 TOASTing 阈值的 2KB 在某种程度上是随意的,并且基于经验。如果您准备好重新编译 PostgreSQL,则可以更改它们(从 PostgreSQL v11 开始,您可以在使用 initdb 创建数据库集群时指定块大小),但我没有听到任何报告说这是个好主意。

    【讨论】:

    • 将旧页面中的空白空间用于新行,影响索引吗?我的意思是,如果在表中,数据是按主索引排序的(你可以说集群索引,虽然据我所知,postgres 不像 sql server 那样纯粹支持它),它不会违反这种情况,在哪里表行按主索引列排序存储?
    • PostgreSQL 中没有主索引。该表是一个无序堆;顺序是通过索引来维护的。每当您UPDATE 一行时,它都会改变位置。也就是说,有CLUSTER 命令以某种方式对表进行排序;这加快了某些查询。
    • 如果 postgres 使用无序堆,那么我猜 postgres 表索引一定是非常碎片化的。而且索引扫描(以及顺序扫描)也必须相对较慢。纠正我,如果我错了。
    • 这取决于你如何定义“碎片化”。表中没有太多不必要的可用空间。顺序扫描非常快,索引扫描不是那么快,因为它们必须以随机顺序访问表。这就是 PostgreSQL 中存在“仅索引扫描”和“位图索引扫描”的原因。
    • “索引扫描”和“仅索引扫描”有什么区别?你说顺序扫描比索引扫描快。这适用于所有情况吗? Postgres 查询计划器是否比索引扫描更优先考虑顺序扫描?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    • 2011-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多