在一个最小的双核 Postgres 实例上运行:查询优化见解
在一个仅有双核的 PostgreSQL 实例上运行整家公司,引发了关于复杂性应该放在哪里的更广泛讨论:是放在谨慎的查询设计和模式优化中,还是直接购买更多数据库容量。评论者争论将逻辑和 joins 下沉到应用层,还是将业务规则和数据完整性保留在数据库中,话题涉及可维护性、性能和 ACID 保证。许多人认为基础的 SQL 素养、索引和查询计划分析被过度忽视;也有人强调,开发者时间和产品市场契合度往往比把数据库的每一分效率都榨干更重要。
微型 Postgres 实例的可行性
- 很多评论者喜欢这个提醒:适度的硬件(2 核、几 GB RAM)也能承载严肃工作负载,呼应了“20 年前我们用更少的资源做了很多事”。
- 有些人把整个应用都跑在非常小的 VM 或廉价 ARM 主机上,并通过精心设计和缓存获得了不错的 TPS/RPS。
- 也有人认为,虽然这很鼓舞人心,但如果云实例扩容相对便宜,这样做可能有些过度优化。
把逻辑从数据库转移到应用层
- 文章里“把逻辑转移到应用层”这句话引发了讨论。
- 批评者说,把 join/filter 移到应用层通常会增加网络 I/O、往返次数和复杂性,还会浪费数据库的优势。
- 支持者则指出一些场景:
- 应用资源比数据库资源更便宜地扩展。
- 可选参数或复杂条件,用几条有针对性的查询来处理,比一条包揽一切的“大查询”更容易。
- 把“指针追逐”式的 joins 拆成多个带索引的查询,可以让系统更“适合 NoSQL”,也更容易缓存。
数据库中的业务逻辑 vs 代码中的业务逻辑
- 一派更偏好大量使用存储过程和约束,这样关键逻辑就是 ACID 的、集中化的、一致的。
- 另一派更偏好“哑数据库”:
- 计算 + 数据混合的工作负载更难剖析和调优。
- 数据库语言生态和工具(类似 PL/SQL)被认为更弱、更难测试、版本化和文档化。
- 分歧的核心是可维护性与强数据完整性之间的取舍,而不只是性能。
查询规划、joins 和索引
- 评论者质疑 nested loop/hash/merge 等 join 方法一般来说“次优”的说法;它们取决于具体场景。
- Postgres 基于成本的规划器有时会选出糟糕的 join 顺序,尤其是在统计信息不佳或 join 很多时;缺少显式 join hint 让一些人感到沮丧。
- 提到的变通方法包括:调优
work_mem、join_collapse_limit、禁用 join 类型(enable_*)、使用WITH MATERIALIZED,以及理解表统计信息。 - 大家普遍同意:理解 SQL、查询计划和索引正变得越来越少见,但至关重要。
成本与优化权衡
- 一方认为:开发者时间远比多几个 CPU 核心或更多内存更昂贵;为了每年省几千块而过度优化,是因小失大。
- 另一方认为:“只要加硬件/上云”的文化会带来巨额的持续账单;基础的查询调优和模式设计应该是标准做法。
- 还有几位强调,持续、适度地关注性能,可以避免日后的危机和 SRE 救火。