pg_squeeze 是 PostgreSQL 的在线表压缩扩展,可在不阻塞业务读写的情况下回收膨胀空间。本文为您介绍基于 pg_squeeze 的在线表空间回收的实践教程。
前置条件
PostgreSQL 15+,wal_level logical。
shared_preload_libraries 包含 pg_squeeze。
至少1个可用复制槽,2倍表大小的存储空间。
表必须有主键或唯一约束,无长事务。
安装配置
关键参数
以下参数必须在控制台参数设置页面配置(postmaster 级别,需重启)。不设置时 Worker 默认以 postgres 连接,腾讯云内核已禁用此行为。
squeeze.worker_autostart:自动启动 Worker 的数据库名,空格分隔。
squeeze.worker_role:Worker 使用的角色。
创建扩展
CREATE EXTENSION IF NOT EXISTS pg_squeeze;
GUC 参数详解
参数名 | 默认值 | 上下文 | 说明 |
squeeze.worker_autostart | 空 | postmaster | 自动启动 Worker 的数据库列表 |
squeeze.worker_role | 空 | postmaster | Worker 使用的角色 |
squeeze.workers_per_database | 1 | postmaster | 每库最大 Worker 数[1,8] |
squeeze.max_xlock_time | 0ms | user | 排他锁最大持有时间 |
squeeze.wait_lock_time | 1000ms | sighup | 等待锁单次最大时间 |
squeeze.quick_quit | off | user | 立即停止 squeeze |
squeeze.allow_superuser | off | sighup | 允许超级用户作为 worker_role |
squeeze.quick_quit 紧急停止开关:
ALTER SYSTEM SET squeeze.quick_quit = on;SELECT pg_reload_conf();
使用方式
手动执行
SELECT squeeze.squeeze_table('public', 'table_name', NULL, NULL, NULL);
注册自动调度
INSERT INTO squeeze.tables (tabschema, tabname, schedule, free_space_extra, min_size, vacuum_max_age, max_retry)VALUES ('public', 'orders',ROW(ARRAY[30]::squeeze.minute[], ARRAY[2]::squeeze.hour[], NULL, NULL, ARRAY[1,2,3,4,5]::squeeze.dow[])::squeeze.schedule,30, 8, '1 hour', 2);
启动/停止:
SELECT squeeze.start_worker();SELECT squeeze.stop_worker();
实战示例
-- 创建测试表并插入50000行CREATE TABLE squeeze_demo (id SERIAL PRIMARY KEY, data TEXT);INSERT INTO squeeze_demo (data) SELECT md5(random()::text) || repeat('x', 200) FROM generate_series(1, 50000);-- 插入后: 15 MB-- 删除2/3数据制造膨胀DELETE FROM squeeze_demo WHERE id % 3 != 0;ANALYZE squeeze_demo;-- 删除后仍 15 MB, 行数 16666-- 执行 squeezeSELECT squeeze.squeeze_table('public', 'squeeze_demo', NULL, NULL, NULL);-- squeeze后: ~5 MB, 回收约10MB(66%)
阶段 | 表大小 | 行数 |
插入后 | 15MB | 50000 |
删除2/3后 | 15MB | 16666 |
squeeze 后 | ≈5MB | 16666 |
回收约66%浪费空间,全程表可正常读写。
监控运维
-- 压缩日志SELECT * FROM squeeze.log ORDER BY started DESC LIMIT 10;-- 错误日志SELECT * FROM squeeze.errors ORDER BY 1 DESC LIMIT 10;-- 活跃WorkerSELECT * FROM squeeze.get_active_workers();-- 已注册表SELECT * FROM squeeze.tables;-- 待执行任务SELECT * FROM squeeze.scheduled_for_now;
关于实践的建议
场景 | 推荐配置 |
生产环境 | worker_autostart=业务库名, worker_role=postgres_admin |
锁时间控制 | max_xlock_time=100 (100ms) |
安全配置 | allow_superuser=off (默认) |
并发控制 | workers_per_database=1 (默认) |
注意:
请注意以下几点:
在业务低峰期执行。
存储空间至少需2倍。
无长事务。
监控 WAL 日志。
避免并行多任务。
分区表逐子表。
保留足够复制槽。
故障排查
Worker 无法启动:请检查 shared_preload_libraries、worker_role 设置、数据库日志。
任务未执行:请检查 squeeze.tables 注册、min_size/free_space_extra 条件。
压缩失败:请查看 squeeze.errors、确认主键、检查长事务和存储空间。