PostgreSQL VACUUM:把膨胀治理当成持续工作

背景 表持续更新之后,查询变慢和空间增长不一定靠加索引解决。旧版本清理、统计信息和长事务都可能影响维护效果。 核心判断 观察死元组估计、autovacuum 时间、事务年龄与维护进度。 区分 VACUUM 清理旧版本和 ANALYZE 更新统计信息的职责。 优先缩短长事务,再按高变化表调整阈值与维护预算。 最小示例 下面保留核心逻辑;业务类型、调用入口和环境配置按项目补齐。 SELECT relname, n_live_tup, n_dead_tup, last_autovacuum FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 20; 边界与误区 n_dead_tup 是估计值,不是精确计数。普通 VACUUM 通常不把空间归还操作系统;VACUUM FULL 会重写并需要强锁,不能当作无风险清理。 验证方式 对持续更新表观察维护前后的大小、计划和延迟;检查被长事务阻挡的清理效果,并评估维护对磁盘 I/O 的影响。 小结 区分 autovacuum 未跟上、长事务阻塞和表设计放大,再按表配置阈值。

2026年10月9日 · 1 分钟 · BvBeJ

PostgreSQL 锁监控:先找阻塞链,再决定处理方式

背景 被阻塞的 SQL 不一定是罪魁祸首,真正的阻塞者可能已经 idle in transaction。排障要先还原阻塞链和事务年龄。 核心判断 用 pg_blocking_pids 获取阻塞者,再关联 pg_stat_activity。 同时观察 wait_event、xact_start 和应用名,判断锁等待来源。 先与业务方确认事务副作用,再决定取消语句或终止会话。 最小示例 下面保留核心逻辑;业务类型、调用入口和环境配置按项目补齐。 SELECT blocked.pid AS blocked_pid, blocker.pid AS blocking_pid, now() - blocker.xact_start AS blocking_xact_age, blocked.wait_event_type, blocked.wait_event, blocked.query AS blocked_query, blocker.query AS blocking_query FROM pg_stat_activity AS blocked CROSS JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS p(pid) JOIN pg_stat_activity AS blocker ON blocker.pid = p.pid ORDER BY blocking_xact_age DESC NULLS LAST; 边界与误区 仅按 locktype 连接 pg_locks 会错误关联不同锁对象。示例使用官方阻塞关系函数;高频查询也有开销,诊断权限与采样频率应受控。 验证方式 建立一个长事务持锁,再让第二个连接等待,核对阻塞 PID 与 SQL。确认取消当前语句和结束整个会话的风险不同,不自动执行终止命令。 小结 监控阻塞者、被阻塞者、事务年龄和 SQL,区分长事务、DDL 与业务冲突。

2026年9月29日 · 1 分钟 · BvBeJ

PostgreSQL 事务隔离:先说明异常,再选择级别

背景 先说需要避免哪一种业务异常,再讨论隔离级别,远比直接选择最高级别有效。库存扣减和账户转账关注的约束并不相同。 核心判断 用并发事务复现丢失更新、写偏差等风险。 能通过原子 SQL、唯一约束或行锁表达的规则,尽量交给数据库。 Serializable 冲突可能导致事务失败,调用方准备有限重试。 最小示例 下面保留核心逻辑;业务类型、调用入口和环境配置按项目补齐。 BEGIN ISOLATION LEVEL SERIALIZABLE; UPDATE accounts SET balance = balance - 10 WHERE id = 1; COMMIT; 边界与误区 示例只有一次扣款,不是完整转账。重试必须从事务开始重新执行,事务外已经发生的副作用也要考虑幂等。 验证方式 使用两个连接安排读写交错,验证业务不变量;对 serialization failure 注入重试,并检查重试预算与外部副作用是否重复。 小结 从业务不变量出发选择隔离级别,并为 serialization failure 准备有限重试。

2026年9月19日 · 1 分钟 · BvBeJ

PostgreSQL 联合索引:左前缀原则不是万能口诀

背景 同一个联合索引有时帮助过滤,有时主要帮助排序。只背左前缀口诀,容易忽略查询实际扫描了多少数据。 核心判断 先列出等值条件、范围条件、ORDER BY 和 LIMIT,再选择列顺序。 检查 EXPLAIN 中的索引条件、过滤行数和排序节点。 同时计算索引对写入、磁盘和维护的成本。 最小示例 下面保留核心逻辑;业务类型、调用入口和环境配置按项目补齐。 CREATE INDEX CONCURRENTLY idx_orders_user_status_created ON orders (user_id, status, created_at DESC); EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = 42 AND status = 'paid'; 边界与误区 索引是否使用以及缺失前导列时是否有收益,要看版本、数据分布和计划。CREATE INDEX CONCURRENTLY 不能放在事务块中,失败后还要检查无效索引。 验证方式 用大租户、小租户和不同状态分别测计划,记录 buffers 与耗时。示例 EXPLAIN ANALYZE 会执行查询,线上需控制成本。 小结 索引列顺序要结合等值过滤、范围条件、排序和实际执行计划决定。

2026年9月9日 · 1 分钟 · BvBeJ

PostgreSQL 表膨胀治理:VACUUM、索引重建与窗口规划

先识别“慢”的来源 SQL 变慢不一定是缺索引,表膨胀和死元组积累会导致扫描范围扩大、缓存命中下降。 治理流程 建立膨胀指标:表大小、死元组比例、索引膨胀率。 调整 autovacuum 阈值与 cost。 对重度膨胀索引做在线重建。 操作原则 大表维护必须做时间窗规划。 避免维护任务与业务高峰重叠。 维护后验证计划变化而非只看时长。 小结 数据库维护不是“定时跑任务”,而是围绕 workload 变化做持续调参和窗口管理。

2026年5月16日 · 1 分钟 · BvBeJ