vm可见性映射

定义:VM 是 PG 中每个表附带的辅助文件,用于快速判断数据块中是否有对所有事务都可见的元组。

核心作用:

  • 加速 VACUUM 操作:跳过全表扫描,只清理包含死元组的块
  • 加速 Index-Only Scan:当 VM 标记某块为"全可见"时,无需回表检查可见性

存储结构:

  • 每个数据块(8KB)在 VM 中对应 2个比特位
  • 第1位:标记该块是否对所有事务可见(全可见块)
  • 第2位:标记该块是否需要被冻结(freeze)

文件位置:$PGDATA/base/<database_oid>/<table_oid>_vm

FSM空闲空间映射

定义:FSM 是 PG 中每个表附带的辅助文件,用于记录每个数据块中的剩余空闲空间。

核心作用:

  • 加速 INSERT/UPDATE 操作:快速定位有足够空间的块,避免遍历所有块
  • 优化空间利用率:优先将新数据填入已有空闲空间

存储结构:

  • 采用树形结构(FSM Tree)组织
  • 叶子节点:记录每个块的剩余空间(0-8192字节)
  • 上层节点:记录子节点中的最大空闲空间
  • 支持快速查找可用块

文件位置:$PGDATA/base/<database_oid>/<table_oid>_fsm

如何往一张表里插入10万行数据,int text,使用一个函数或随机值,一条sql

VM、FSM怎么创建的
  • VM 文件:只在需要时才创建(第一次 VACUUM 或第一次 Index-Only Scan 时)
  • FSM 文件:只在需要时才创建(第一次 INSERT 或 UPDATE 需要查找空闲空间时)
执行 VACUUM(会触发 VM 和 FSM 更新)
VACUUM tablename;
VACUUM (VERBOSE, ANALYZE) tablename;
## VERBOSE=输出详细执行日志

实验

1.创建数据库mydb1,查看当前数据库的 OID 和表空间位置
create database mydb1;
select oid,datname from pg_database;

2.创建测试表test_vm_fsm,找到表在OS层文件对应位置

在新建表时不会产生fsm和vm文件,直到pg执行VACUUM操作时,或者第一次使用 fsm或vm 文件时才会生成。

create table test_vm_fsm (id int,name varchar(100));

SELECT oid, relname, relpages, relallvisible
FROM pg_class 
WHERE relname = 'test_vm_fsm';

3.插入一万行数据
INSERT INTO test_vm_fsm (id, name)
SELECT
    generate_series(1, 100000),
    'test_' || md5(random()::text);

4.查看对应的vm、fsm文件生成
SELECT
  relname 表名,
  n_live_tup 存活行数,
  n_dead_tup 死元组行数,
  pg_size_pretty(pg_total_relation_size(relid)) 总占用空间
FROM pg_stat_user_tables
WHERE relname = 'test_vm_fsm';

*5.删除部分数据,再查看vm统计信息、查看fsm块状态
删除
DELETE FROM test_vm_fsm
WHERE id IN (
    SELECT id FROM test_vm_fsm
    ORDER BY random()
    LIMIT 1000
);

SELECT oid, relname, relpages, relallvisible
FROM pg_class
WHERE relname = 'test_vm_fsm';

VM

relpages = 表占用的总数据块数,relallvisible 是 VM 文件标记为全部可见的块数

删除数据后vm/fsm文件大小在OS层无变化,表示删除数据仅把行标记为无效,依然占用空间

FSM

安装PG扩展,查看FSM内部信息

CREATE EXTENSION pg_freespacemap;
CREATE EXTENSION pg_visibility;
SELECT * FROM pg_available_extensions WHERE name = 'pg_freespacemap';
SELECT * FROM pg_available_extensions WHERE name = 'pg_visibility';

SELECT blkno, avail 
FROM pg_freespace('test_vm_fsm'::regclass) 
ORDER BY avail 
LIMIT 10;

blkno:数据块号(PG 默认每个块 8KB = 8192 字节)

aiail:块中还剩多少字节

可以看出每个8kb的块剩余32字节,几乎写满,删除只是标记删除,所以几乎没有空闲空间

6.进行vacuum,查询*5的命令
VACUUM test_vm_fsm;

SELECT
  relname 表名,
  n_live_tup 存活行数,
  n_dead_tup 死元组行数,
  pg_size_pretty(pg_total_relation_size(relid)) 总占用空间
FROM pg_stat_user_tables
WHERE relname = 'test_vm_fsm';

SELECT blkno, avail 
FROM pg_freespace('test_vm_fsm'::regclass) 
ORDER BY blkno 
LIMIT 10;

vacuum后死元组已被清理,已删除部分空间成功释放,OS层文件大小不变

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐