MySQL查询优化案例

先看原始SQL(简化版):

随手EXPLAIN了一下,好家伙,type显示ALL,全表扫描!key字段为NULL,根本没用到索引。再看rows列,扫描行数接近700万,不慢才怪。

仔细分析WHERE条件中的字段:register_time、level、last_login、status,还有个ORDER BY register_time。直觉告诉我应该在register_time上建索引,毕竟它既有范围查询又参与排序。但事情没这么简单。

先试着加了个单字段索引:

再次执行查询,发现虽然用上了这个索引,但效果不明显。原来这个索引只能帮我们快速定位到某个时间段的记录,后面的level、last_login、status过滤还是得回表逐条判断。

看来需要复合索引。这时候就要考虑字段的顺序了,经典的“最左前缀”原则得用上。把范围查询的字段放在后面可能更合适,因为范围查询之后的索引列会失效。

根据这个思路,我设计了这样的索引:

为什么这么设计?让我解释一下:

把等值查询的status和level放前面,因为它们都能充分利用索引

register_time虽然也是范围查询,但因为它要参与排序,所以必须出现在索引中,且顺序要和ORDER BY一致

last_login作为另一个范围查询条件放在最后

建完索引再EXPLAIN,效果立竿见影:type变成range,扫描行数从700万降到不到1万,Extra显示Using index condition。查询时间从原来的12秒多降到0.2秒左右!

不过还有个细节要注意,原来的BETWEEN查询我改成了:

虽然效果一样,但BETWEEN在某些情况下可能不会充分利用索引,这种写法更稳妥。

另外,由于查询中SELECT的字段不多,如果把这个索引改成覆盖索引,性能还能进一步提升:

这样连回表操作都省了,查询时间可以降到0.1秒以内。

经过这番优化,业务方终于不再抱怨了。总结几点经验:一是别盲目建单字段索引,要多考虑复合索引;二是索引字段顺序很重要,等值在前,范围在后;三是如果查询字段不多,尽量使用覆盖索引避免回表。当然每个场景都不一样,最终还是要用EXPLAIN来验证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值