PostgreSQL 基础:索引、事务、慢查询怎么理解
更新说明:补充 PostgreSQL 基础和慢查询排查思路。
系列:Python Web 工程实践
- Python Web 项目配置管理:环境变量、.env 和生产配置怎么拆
- Python Web 项目如何连接数据库:SQLAlchemy、Django ORM、迁移怎么选
- Alembic 数据库迁移入门:表结构变更怎么安全上线
- Django 数据库迁移实战:makemigrations 和 migrate 背后的坑
- FastAPI 项目测试指南:pytest、TestClient、依赖覆盖怎么用
- Django 测试入门:Model、View、API 测试怎么写
- FastAPI 分层架构:router、service、repository 怎么拆
- PostgreSQL 基础:索引、事务、慢查询怎么理解
很多 Web 项目一开始只关心“数据库能不能连上”,后来才会遇到查询慢、重复数据、事务不一致、迁移变慢这些问题。PostgreSQL 不需要一开始学得很深,但有几个基础概念越早理解越好。
这篇只讲 Web 项目最常用的三件事:索引、事务、慢查询。
索引不是越多越好
索引可以让查询更快,但它不是免费午餐。每多一个索引,写入和更新时数据库都要维护它。
常见的适合建索引的字段:
- 经常出现在
where条件里的字段 - 经常用于排序的字段
- 外键字段
- 唯一约束字段
- 高频组合查询字段
create index idx_articles_status_created_aton articles (status, created_at desc);如果接口经常这样查:
select *from articleswhere status = 'published'order by created_at desclimit 20;上面的组合索引就可能有用。
用 explain 看执行计划
不要靠感觉判断索引是否生效。先看执行计划。
explain analyzeselect *from articleswhere status = 'published'order by created_at desclimit 20;常见关键词:
Seq Scan:顺序扫描整张表Index Scan:使用索引扫描Bitmap Index Scan:先用索引找位置,再回表Sort:额外排序
小表出现 Seq Scan 不一定是坏事。数据量很小时,全表扫可能比走索引更便宜。
事务解决什么问题
事务保证一组操作要么都成功,要么都失败。最典型的例子是创建订单和扣库存。
begin;
insert into orders (user_id, total) values (1, 99);update products set stock = stock - 1 where id = 10;
commit;如果中间出错,可以回滚:
rollback;在 Web 项目里,事务边界要清楚。不要在一个事务里做很慢的外部请求,也不要让事务跨越太多不相关逻辑。
唯一约束比代码判断更可靠
比如用户名不能重复,不能只靠代码先查一遍。
create unique index users_email_key on users (email);代码里的“先查再插入”在并发下可能失效。数据库唯一约束才是最终防线。
慢查询先看三件事
排查慢查询时,我会先看:
- 数据量是否比预期大
- where 和 order by 是否有合适索引
- 是否查出了太多不需要的列或行
比如接口只展示标题和时间,就不要 select *。
select id, title, created_atfrom articleswhere status = 'published'order by created_at desclimit 20;分页也要注意。很深的 offset 会越来越慢。
select id, titlefrom articlesorder by idlimit 20 offset 100000;数据量大时,可以考虑基于游标的分页。
Web 项目里常见的坑
第一个坑是 N+1 查询。列表页查出 20 篇文章,然后每篇文章再单独查作者,就会变成 21 次查询。
第二个坑是模糊搜索。like '%keyword%' 很难用普通 B-tree 索引优化,需要考虑全文搜索或 trigram 索引。
第三个坑是迁移时给大表加字段、加索引。数据库迁移可以接着看 Alembic 数据库迁移入门:表结构变更怎么安全上线 和 Django 数据库迁移实战:makemigrations 和 migrate 背后的坑。
总结
PostgreSQL 的基础不只是 SQL 语法。对 Web 项目来说,索引决定查询路径,事务决定数据一致性,慢查询排查决定线上稳定性。
刚开始不需要把数据库调优学得很深,但要养成两个习惯:用约束保护数据,用 explain analyze 验证判断。这样遇到性能问题时,至少不会只靠猜。