四、PostrgeSQL空闲空间地图

Free Space Map(FSM)是 PostgreSQL 用来记录每个数据页"还剩多少可用空间"的辅助结构。它让 INSERT / UPDATE 能快速找到可复用的页面,避免盲目扩展表文件。

Free Space Map 使用树形结构为每个 Heap Page 记录一个字节的近似空闲空间等级,让 INSERT / UPDATE 能快速定位可复用页面,避免逐页扫描或不必要地扩展表文件。查看 FSM 内容应优先使用 pg_freespacemap 扩展。

1. FSM 保存在哪里?

每个 heap relation 的存储由多个 fork 组成。假设表的 relfilenode16384
16384
主数据文件(main fork)
16384_fsm
空闲空间地图(FSM fork)
16384_vm
可见性地图(VM fork)
查看各 fork 大小:
SELECT
    pg_size_pretty(pg_relation_size('public.test', 'main')) AS main_size,
    pg_size_pretty(pg_relation_size('public.test', 'fsm'))  AS fsm_size,
    pg_size_pretty(pg_relation_size('public.test', 'vm'))   AS vm_size;
FSM 不是整个数据库共享一个文件,而是每个有需要的 relation 都有自己的 FSM fork。表、TOAST 表和部分索引访问方法都可能使用各自的 FSM。

2. FSM 记录的是什么?

对于 Heap 表,FSM 主要记录每个 Heap Page 大约还有多少可用空间。例如:
Heap Page
剩余空间
Page 0
200 bytes
Page 1
3000 bytes
Page 2
7000 bytes
Page 3
1000 bytes
如果 PostgreSQL 需要插入一个约 2 KB 的 tuple,就可以通过 FSM 快速定位到 Page 1 或 Page 2,而不需要依次读取并检查所有 Heap Page。

3. FSM 为什么能快速查找页面?

FSM 不是简单地把所有 Heap Page 顺序列出来,而是使用树形结构。可以简化理解成:
                    7000
                  /      \
              3000        7000
             /    \      /    \
Page 0:200  P1:3000  P2:7000  P3:1000
每个父节点保存子节点中的最大空闲空间。查找至少有 2 KB 空间的页面时:
  1. 从根节点开始
  2. 选择最大空闲空间不小于 2 KB 的分支
  3. 一直向下查找,最终定位到具体 Heap Page
  4. 读取 Heap Page,再验证真实空间
如果找不到足够空间,PostgreSQL 通常会扩展表文件,创建新的 Heap Page。

4. INSERT 如何使用 FSM?

执行一条简单的插入:
INSERT INTO test VALUES (1, 'abc');
大致过程如下:
    A[计算新 tuple 所需空间] --> B[查询 FSM]
    B --> C[找到可能有足够空间的 Heap Page]
    C --> D[读取并锁定该 Heap Page]
    D --> E{检查真实空闲空间}
    E -->|空间足够| F[插入 tuple]
    E -->|空间不足| G[更新 FSM,继续寻找]
    G --> B
    E -->|没有合适页面| H[扩展表文件]

5. DELETE 后空间会立即出现在 FSM 中吗?

通常不会立即完全变成可复用空间。
DELETE FROM test WHERE id = 1;
被删除的 tuple 先成为 dead tuple,但它占用的空间暂时不能直接重用——其他持有旧快照的事务可能仍然需要看到它。
    A[DELETE] --> B[旧 tuple 变成可能死亡的版本]
    B --> C[等待不再被任何事务需要]
    C --> D[页面剪枝或 VACUUM 清理]
    D --> E[空间变为可复用]
    E --> F[FSM 更新]
因此:
DELETE FROM test;
不会立刻缩小表文件,也不一定立刻让 FSM 显示出全部空闲空间。执行 VACUUM 可以清理 dead tuple 并更新 FSM:
VACUUM test;
普通 VACUUM 通常只是让空间可供 PostgreSQL 内部复用,不会把整个表文件空间返还给操作系统。

6. UPDATE 和 FSM 的关系

PostgreSQL 的 UPDATE 实际上会创建一个新的 tuple 版本。
优先情况:新版本能放在原来的 Heap Page 中,如果满足索引等条件,还可能形成 HOT Update(Heap-Only Tuple Update)。- 这是什么意思?待更新
非优先情况:如果原页面空间不够,PostgreSQL 通过 FSM 查找其他页面:
    A[原页面空间不足] --> B[通过 FSM 查找其他页面]
    B --> C[将新 tuple 版本写入其他页面]
    C --> D[无法形成 HOT Update]
    D --> E[索引可能需要加入新的索引项]

7. 如何查看 FSM 内容?

最方便的是使用 pg_freespacemap 扩展。

安装扩展

CREATE EXTENSION pg_freespacemap;

查看所有页面的近似可用空间

SELECT * FROM pg_freespace('public.test');
select *, round(100 * avail/8192, 2) as "freespace ratio" from pg_freespace('test1');
结果类似:
blkno
avail
0
1024
1
4096
2
8160
其中 blkno 是 Heap Page 编号,avail 是 FSM 认为该页面大约有多少字节可用。

查看指定 Heap Page

SELECT pg_freespace('public.test', 0);
 
posted @ 2026-08-30 08:36  BinBin-HF  阅读(7)  评论(0)    收藏  举报