PostgreSQL:行大小超过页面剩余空间时的存储机制问询
PostgreSQL页面存储与TOAST机制答疑
嘿,这两个问题刚好触及了PostgreSQL存储引擎的核心逻辑,我来给你拆解清楚:
1. 当行大小超过页面可用空闲空间时,PostgreSQL如何存储行?
首先要明确:PostgreSQL不会硬把大行数塞进空间不足的页面,它会先触发TOAST机制来处理大字段,而非整个行。具体流程是这样的:
- 第一步:尝试压缩行中的大字段(比如TEXT、BYTEA这类容易超标的类型)。PostgreSQL会用LZ算法压缩这些字段,如果压缩后的行能刚好放进当前页面的空闲空间,就直接存储压缩后的行。
- 第二步:如果压缩后还是放不下,就会把**单个大字段(而非整行)**迁移到专门的TOAST表中。原页面里只会保留一个很小的"引用指针"(包含TOAST表的OID、字段物理位置等元数据),这样原行的总大小就会缩减到能放进当前页面的程度。
- 额外注意:TOAST只针对行中的大字段生效,不是整行迁移——如果行里只有一个字段特别大,其他字段还是会留在原页面,只有那个大字段去TOAST表"安家"。
2. 当前页面仅剩余1K空间,新建行大小超过1K时的处理逻辑
这里得分两种核心情况来看:
情况A:新建行的总大小未超过单个页面的最大容纳量(约8KB减去页面元数据,大概8100字节左右)
这种情况下,PostgreSQL会触发页面分裂(Page Split):
- 系统会分配一个全新的空页面,然后把原页面中大约一半的行迁移到新页面,这样原页面和新页面都会腾出足够的空闲空间。
- 之后把新行插入到合适的页面(可能是原页面,也可能是新页面,取决于行的排序键和页面的存储顺序)。
- 旧页面不会被丢弃,它依然属于这个表的磁盘块集合,和新页面通过内部链表指针关联,后续依然会用来存储符合条件的行数据。
情况B:新建行的总大小超过了单个页面的最大容纳量
这时候页面分裂也解决不了问题——毕竟哪怕空页面都放不下整行,这时候就会触发前面说的TOAST机制:
- 先对行中的大字段进行压缩,如果压缩后能放进单个页面,就正常插入(可能还是需要页面分裂来腾出空间);
- 如果压缩后还是超标,就把大字段移到TOAST表,原行只保留引用指针,直到行的总大小符合页面存储要求,再进行页面分裂或插入操作。
内容的提问来源于stack exchange,提问作者Mangu Singh Rajpurohit
相关产品推荐
相关产品推荐

