04 开发者必备 PostgreSQL SQL 与数据库编程能力

对很多应用开发者来说,数据库只是“存取数据的地方”。这正是系统后来越来越慢、越来越难维护的重要原因。真正高效的 PostgreSQL 使用方式,是尽可能让数据库完成它擅长的集合计算、一致性控制和近数据处理,而不是把大量数据搬到应用层再做二次加工。

先建立一个判断标准

下面这类事情,优先考虑交给 PostgreSQL:

  • 批量过滤、聚合、排序、分组
  • 基于唯一约束的幂等写入
  • 一次事务内的一致性更新
  • 与数据强相关的派生值生成
  • 审计、回写、状态迁移等数据库内逻辑

下面这类事情,更适合留在应用层:

  • 复杂业务流程编排
  • 跨系统调用
  • 长耗时外部交互
  • 高度可变、难以稳定抽象的业务规则

这条边界一清楚,数据库编程就不容易走偏。

开发者最该先学会的 SQL 能力

1. 批量写入和幂等写入

很多系统性能差,不是数据库不行,而是应用一行一行写。

应该优先掌握:

insert into users (id, name, email)
values
  (1, 'a', 'a@test.com'),
  (2, 'b', 'b@test.com')
on conflict (id) do update
set name = excluded.name,
    email = excluded.email;

这比应用层循环更新更稳,也更容易保证幂等。

2. returning

写入后立即拿结果,是 PostgreSQL 很实用的能力。

insert into orders (user_id, status, amount)
values (1001, 'pending', 99.00)
returning id, created_at;

别再额外查一次。

3. 窗口函数

很多“排行榜、去重取最新、按组排序”问题,如果不会窗口函数,就会在应用层写出一堆低效代码。

select *
from (
  select
    o.*,
    row_number() over (partition by user_id order by created_at desc) as rn
  from orders o
) t
where rn = 1;

4. 公共表达式和可读性

with 不是性能魔法,但它是很好的可读性工具。复杂 SQL 如果分层写清楚,后面调试和解释都会轻松很多。

函数、存储过程、触发器什么时候值得用

适合用函数或过程的场景

  • 多个服务都要复用同一段数据库逻辑
  • 一组写操作必须在数据库内部一次完成
  • 需要把某些规则放到最靠近数据的位置

不适合滥用的场景

  • 业务流程变化很快
  • 涉及大量外部调用
  • 团队没有数据库代码审查和版本管理习惯

原则很简单: 数据库编程要服务于“降低复杂度”,而不是制造第二套难维护的应用系统。

触发器最容易出的问题

触发器的危险不在于它不好用,而在于它“太隐蔽”。

常见问题包括:

  • 应用写一条语句,却触发了一串隐式动作
  • 批量导入时被触发器拖慢
  • 审计逻辑藏在触发器里,团队并不知道

所以,触发器适合做少量、明确、稳定的事情,比如更新时间戳、轻量审计、简单派生字段。超过这个边界,就该谨慎。

开发者写 SQL 时最值钱的习惯

  • 用集合思维代替循环思维
  • 用约束保证正确,而不是只靠代码约定
  • 用一条高质量 SQL 代替多次往返
  • 把可读性当成性能优化的前提

SQL 能力不是“会写语法”,而是能不能把数据问题变成数据库擅长解决的问题。这恰恰是 PostgreSQL 最值得学的地方。