打开网易新闻 查看精彩图片

2024年Stack Overflow调研显示,数据库性能问题占后端工程师日常排障的34%。更扎心的是,其中62%的慢查询只需改3-5行代码就能提速10倍以上——但大多数人根本不知道问题出在哪。

这像什么?就像你开着一辆油门卡死的跑车,天天骂车不行,其实只需要把脚垫挪一下。

索引不是越多越好,是越准越好

索引不是越多越好,是越准越好

索引(Index,数据库的"目录页")被奉为SQL优化的银弹,但滥用它比不用更惨。我见过一个电商系统给20个字段建了单独索引,写入速度慢得像在刻光盘。

核心原则:单列查询建单列索引,组合查询建组合索引。

CREATE INDEX idx_email_created ON users(email, created_at);

这条语句解决的是真实场景——用户按邮箱查,还要筛选注册时间。数据库直接定位到数据块,而不是翻完整本"电话簿"。

代价也很直白:每多一个索引,INSERT和UPDATE就多一笔维护开销。生产环境建议用监控工具(如MySQL的Performance Schema)定期审计,删掉半年没被用过的索引。

SELECT * 是性能刺客

SELECT * 是性能刺客

SELECT * FROM users 写起来爽,跑起来哭。一个用户表如果有头像二进制字段,你查邮箱列表时把图片也拖进内存,带宽和内存双杀。

正确姿势是明确列名:

SELECT email FROM users WHERE created_at > '2025-01-01';

打开网易新闻 查看精彩图片

这个习惯在微服务架构里尤其重要。服务A调服务B的API,如果B返回了全量字段,A的内存占用会随数据量线性膨胀,直到OOM崩溃。

更隐蔽的坑是ORM框架。很多开发者用User.objects.all()时,框架底层就是SELECT *。检查你的ORM文档,学会用.only()或.select_related()精确控制字段。

把过滤逻辑推给数据库

把过滤逻辑推给数据库

新手常犯的错:先SELECT *,再在代码里用if过滤。数据量小的时候没事,上了生产就是灾难。

对比两行代码:

-- 烂代码:拖10万行到内存,过滤剩100行

SELECT * FROM users;

-- 好代码:数据库只返回100行

SELECT * FROM users WHERE created_at >= '2026-01-01';

SQL引擎为过滤做了深度优化:索引裁剪、分区剪枝、并行扫描。你把数据拖到应用层再处理,等于放着数控机床不用,拿手锯切钢板。

唯一例外是复杂业务规则。如果过滤条件涉及多个表关联后的计算结果,有时分批查询+内存处理反而更快。但这需要EXPLAIN验证,不是拍脑袋决定。

EXPLAIN是你最该学的命令

EXPLAIN是你最该学的命令

打开网易新闻 查看精彩图片

EXPLAIN(执行计划分析)被严重低估。它告诉你数据库怎么执行查询,就像导航软件的路线预览。

运行 EXPLAIN SELECT * FROM users WHERE email = 'alice@example.com',重点看两个词:

Index Scan = 走索引,快

Seq Scan = 全表扫描,慢

看到Seq Scan先别慌。小表全扫可能比索引跳转更快,因为索引本身有查找开销。但超过几千行的表还出现Seq Scan,就该警惕了。

PostgreSQL的EXPLAIN ANALYZE会实际执行并计时,MySQL的EXPLAIN FORMAT=JSON能输出更详细的成本估算。选一个你数据库支持的,写进日常开发流程。

N+1问题:ORM时代的经典陷阱

N+1问题:ORM时代的经典陷阱

原文没展开,但这值得补一刀。N+1问题指:查1个列表,再循环查N次详情。比如先查100个用户,再逐个查他们的订单数——101次查询。

解法是用JOIN或子查询一次性拿完:

SELECT u.*, COUNT(o.id) as order_count

FROM users u LEFT JOIN orders o ON u.id = o.user_id

GROUP BY u.id;

现代ORM都有批量加载方案:Django的prefetch_related,SQLAlchemy的selectinload。不知道这些,你的API响应时间会从50ms变成5秒,而代码看起来"完全没毛病"。

最后留一个问题:你上次用EXPLAIN分析慢查询是什么时候?如果答案是"没用过"或"半年前",建议今天挑一条生产环境的慢SQL试试——结果可能会让你重新评估自己的索引设计。