做开发的,谁没被慢查询折磨过?数据库崩了,页面转圈,老板在后面盯着你脖子发凉。我刚入行那会儿,一个简单的报表查询跑了三分钟,气得运维大哥直接拔网线。后来摸爬滚打,从看执行计划到调索引,总算把查询从分钟级压到毫秒级。这5个技巧,是我踩坑踩出来的真功夫,今天掏心窝子分享给你。

第一个技巧:别让数据库做全表扫描,索引不是万能药,但没索引万万不能。很多人建索引就是拍脑袋,看到查询慢就往where条件上扔个普通索引。结果呢?索引覆盖不到位,回表查询照样慢。比如你查用户订单,select from orders where userid = 123,这没问题,但如果你只查orderid和amount,就别写星号。建个联合索引(userid, amount),数据库直接走索引覆盖,连表都不回,速度翻倍。我见过一个案例,电商平台查订单详情,加了个覆盖索引后,查询从800毫秒降到20毫秒。记住,索引不是越多越好,但关键查询没索引,就是自掘坟墓。
第二个技巧:避免在where条件里做函数运算,这玩意儿是索引的杀手。比如where date(createtime) = '2024-01-01',你以为数据库聪明到会用索引?不,它老老实实扫全表,因为函数让索引失效。改成where createtime >= '2024-01-01' and createtime < '2024-01-02',索引立马生效。还有个坑,where name like '%张三%'也是全表扫描,因为前缀模糊匹配不走索引。真想搜文本,上全文索引或者Elasticsearch。我调过一个系统,日志表每天几百万条,开发写了个where datediff(now(), createtime) < 30,查询跑了几十秒。改成范围查询后,一秒不到出结果。函数运算别碰,这是铁律。
第三个技巧:分页查询别用offset硬跳,越往后越慢。select from orders limit 100, 20,数据库得先扫描10万行再扔掉,白费功夫。换成游标分页:select from orders where id > 100 limit 20,或者用between and。前提是id有序,如果业务允许就用这个。我优化过一个后台管理系统,翻页到后面直接超时,改成游标分页后,响应时间稳定在50毫秒以内。当然,如果前端非要随机跳页,那就用覆盖索引先查id,再关联主表:select from orders where id in (select id from orders order by createtime limit 100, 20)。这样扫描量小很多。分页优化是硬需求,别偷懒。
第四个技巧:巧用EXPLAIN看懂执行计划,这才是数据库给你的体检报告。很多人遇到慢查询就瞎猜,加索引、改sql,全靠蒙。EXPLAIN一下,type列是ALL就是全表扫描,range或ref就是走索引,rows列预估扫描行数,Extra列有Using filesort就要注意排序优化。我有个习惯,每条新写的sql都先explain一遍,看有没有潜在问题。比如join查询,驱动表和被驱动表选错,结果扫描行数差十倍。用force index指定索引,或者调整join顺序,都能优化。有一次,一个关联查询explain显示rows=500万,实际数据才10万,原来是统计信息不准,跑个analyze table就正常了。执行计划是你的第三只眼,别省这一步。
第五个技巧:事务别开太大,锁和死锁是慢查询的隐形杀手。很多人写业务逻辑,一个事务里塞几十条更新,中间还查别的表。结果锁范围扩大,其他会话排队等锁,系统吞吐量直接腰斩。优化思路:能拆小事务就拆,每条更新独立提交;或者用乐观锁,减少锁竞争。还有个常见问题,update where条件没索引,直接锁表,并发一高就死锁。我调过一个支付系统,事务里先查用户余额再扣款,改成一条update语句加条件判断,不仅减少一次查询,还锁行不锁表。事务粒度要细,锁范围要窄,这是高并发的基础。
说完了这5个技巧,你可能觉得都是老生常谈。但真正落地的时候,很多开发就是记不住。比如索引覆盖,你建个联合索引,查询时少回表一次,性能提升立竿见影。再比如分页优化,你以为用户只看前几页,但后台导出功能动不动就翻到几十万页。这些细节,决定了数据库是在飞还是在爬。
我送你一句话:SQL优化不是玄学,是工程。从慢查询到毫秒响应,靠的不是运气,是每个索引、每个explain、每个事务的精心打磨。下次数据库再崩,别慌,拿出这5招,一个个排查。保准你老板看你代码的眼神,从嫌弃变成欣赏。数据库起飞了,你也就起飞了。


