客户发来消息:「网站又转圈圈了,是不是该升级服务器了?」十次里有七次,问题不在服务器,在慢查询。数据量涨到几十万行之后,数据库设计阶段欠下的索引债,开始连本带利地讨。
先找到慢的那条SQL
优化第一步永远是定位,不是瞎猜。开启MySQL的慢查询日志,阈值先设一秒,跑两天,日志里反复出现的那几条SQL就是目标。很多团队嘴里的「数据库很慢」,最后定位下来就两三条SQL,改完世界清净,一分钱没花。
索引不是越多越好
见过有人给一张表的二十个字段各建了一个索引,写入性能直接被拖垮——每写一行要同步维护二十棵索引树。索引该建在哪?给where条件、order by、join关联字段建,其他别碰。性别、状态这种只有两三个取值的字段,单独建索引没用,区分度太低,优化器根本不会用它,白占空间。
联合索引,顺序有讲究
查询条件经常是「用户ID加状态加时间」,建一个三列联合索引比建三个单列索引强,但列的顺序必须遵守最左前缀原则:把最常查询、区分度最高的列放最左。查user_id加status能用上索引,只查status则用不上。建联合索引前,先把手头SQL的条件组合统计一遍再定顺序,别拍脑袋。
改完要验证,别凭感觉
加完索引用explain看执行计划,确认type从ALL变成了ref或range,rows数量明显下降,才算真生效。没这一步,加没加对全凭感觉,回头线上该慢还是慢,还以为索引是玄学。
还有个常见误区提一下:有人爱在时间字段上加函数查询,比如按月统计时对created_at套日期函数,这种写法会让索引直接失效,明明建了索引照样全表扫。改成范围查询,比如查某天零点到次日零点之间,索引立刻就活了。一条SQL的写法差别,性能差几十倍,这不是玄学,是机制。
两条建议:每月固定看一次慢查询日志,当成例行保养;新功能上线前,让开发对涉及大表的SQL跑一遍执行计划再发布。比格网络给客户做性能排查时,处理慢查询比升级服务器省钱得多,先回头优化数据库设计再花钱扩容,这个顺序别搞反。