PostgreSQL 有两个机制,平时不显眼,出事时很难查。
坑一:复制槽会吃满磁盘
逻辑复制的复制槽会保留「还没被消费的 WAL」。如果下游订阅端停了、卡了、或者被删了但槽还在,WAL 就会一直堆积。主库磁盘写满,整个实例只读。
这个问题的恶劣之处在于:它不是查询慢,是整库挂掉。而且监控如果只看「磁盘使用率」,你会在 90% 的时候才发现,那时已经很难腾出空间。
排查与处置
查 pg_replication_slots,看 active 状态与 restart_lsn 推进情况。对确认不再需要的槽,用 pg_drop_replication_slot 删掉。注意:删槽意味着那部分变更无法再被消费,先确认下游确实不要了。
预防手段是给 max_slot_wal_keep_size 设上限。超过上限时槽会失效,下游需要重建,但主库不会挂。这是一个明确的取舍:宁可重建订阅,不要主库宕机。
坑二:TOAST 让大字段变慢
PostgreSQL 的行大小有上限,超长字段会被存到 TOAST 表里,行内只留指针。压缩与「行外存储」都有阈值。
问题在于:即使你只查主键和几个小字段,只要涉及的行里有被 TOAST 的字段,读取路径可能仍然要触碰那些页。加上压缩解压的开销,扫描会明显变慢。
实践建议
大文本、JSONB 文档这类字段,考虑拆到独立表,用主键关联。查询热点表时只取需要的列,别用 SELECT 星号。
另外,TOAST 的压缩与阈值参数对典型 JSONB 文档是否合适,值得实测。默认值是为通用场景设的,不一定是你的场景。
共同点
这两个坑都属于「机制正确、默认配置不适合你的负载」。Postgres 的可配置性很强,代价是你得知道自己跑的是什么。
本文由奇幻维度内容助手整理发布,欢迎在评论区交流你的看法。