从慢查询开始说起
你有没有遇到过这样的情况:用户点开一个页面,转圈等了五六秒才出来数据?后台日志一查,一条 SQL 执行了 4 秒。这种情况在数据量上来之后特别常见,尤其是订单、日志这类表,一个月下来几百万条记录,全靠 SELECT * 撑着,系统不卡才怪。
其实大多数性能问题,不是数据库不行,而是查询写得太糙。优化它,不需要换硬件,也不用上分布式,先从最基础的改起。
给字段加索引,但别乱加
索引就像书的目录,没有它就得一页页翻。比如你要查某个用户的订单,WHERE user_id = 1001,如果 user_id 没有索引,数据库就得扫全表。数据一多,这代价就扛不住。
加个索引很简单:
CREATE INDEX idx_user_id ON orders (user_id);但注意,索引不是越多越好。每加一个索引,写入数据时就要多维护一棵树,INSERT、UPDATE 变慢。特别是那些更新频繁又很少用来查询的字段,别盲目建索引。
避免 SELECT *
很多人写 SQL 图省事,直接 SELECT * FROM users。可你真需要所有字段吗?有时候只显示用户名和邮箱,却把加密密码、个人简介这些大字段也捞出来,浪费 I/O 和内存。
改成明确字段:
SELECT id, username, email FROM users WHERE status = 1;既减少传输量,又可能走覆盖索引,效率提升明显。
合理使用 LIMIT
分页查数据时,别忘了加 LIMIT。曾经见过有人写后台列表,不加限制直接拉前一万条,页面卡死不说,数据库连接池都被占满。
哪怕前端暂时没做分页,后端也该设个保护值:
SELECT id, title FROM articles ORDER BY created_at DESC LIMIT 50;要查更多?带上 offset 或者用游标分页,别一口气全拿。
拆解复杂查询
有些报表需求,动不动就是五六个表 JOIN,还套子查询。这种 SQL 看着厉害,执行起来特别容易走错执行计划,索引失效,临时表往磁盘一丢,速度直接掉底。
不如拆成几步,先查主数据,再用 IN 拿关联信息。虽然多几条语句,但每条都能走索引,总耗时反而更短。
利用缓存绕开查询
有些数据变化不频繁,比如商品分类、城市列表,每次都要查数据库纯属浪费。加一层 Redis 缓存,第一次查完存起来,后面直接读,响应从几百毫秒降到几毫秒。
缓存不是万能,得考虑一致性。但对读多写少的场景,效果立竿见影。
定期看慢查询日志
MySQL 开启 slow query log,把超过 1 秒的语句记下来。每周花半小时扫一眼,往往能发现被忽略的问题 SQL。可能是个没走索引的查询,也可能是个缺失的复合索引。
发现问题后,用 EXPLAIN 分析执行计划,看看是不是走了全表扫描,或者临时文件排序。
优化数据库查询,本质上是养成好习惯。别图一时方便写烂 SQL,等到系统撑不住再回头,代价更大。