近期工作中遇到不少代码执行速度偏慢,通常这部分慢速代码都是由于SQL语句使用不当造成的。如何改善SQL的执行质量,是一个优秀PHP程序猿的必备技能。
普遍遇到的慢SQL有以下三种:
1.未走索引
2.where条件里包含子查询,多表联查
3.查询大量数据
根据我的一些工作经验,对这几种情况进行了总结,并在实践中发现了提升它们执行效率的方法。
一.索引:SQL中的高速公路
但凡优化SQL,首先要看的就是这条查询是否走了索引。走索引的查询和没走索引的差距可谓云泥之别。
可以看下面这个例子:
在一张大约3W数据量的用户表中,两种查询方式在速度上的差距:
不走索引:
select * from kw_user_copy where new_id=1 时间: 0.321 s
走主键索引:
select * from kw_user_copy where id=1 时间: 0.002 s
执行时间上有着数百倍的差距。
这种差距如果放在一些大的嵌套中,譬如循环查询500次,将成为非常致命的问题,甚至可能让程序执行超时。
PS. 很多查询条件也会导致SQL放弃索引而执行全表遍历,譬如:
select id from item where num is null
这些细节也要引起注意。
看到这里,很多有经验的程序猿都会表示:“索引太基础了,是个人都会用啊”。
其实不然,在很多时候我们会存在一些盲点,从而忽略一些“本可以走的索引”,导致了SQL查询的效率低下。
实际项目中的例子:
select id as user_id, name, nickname, photo, status, sdk_key, sdk_status from kw_user where name = 'wallkop' AND password = '44209a6a592dea91bcf7d4dd53e47a5a' 时间: 0.247 s
这是一条非常常见的用户登录查询。
直观看起来,这条SQL似乎写的非常完善了,根据name和password去查询相关用户的信息,怎么看都没有优化的余地了。
我们也知道:name和password作为两个string字段,通常是不会建立索引的,也就是说,这是一条必然不走索引的查询。
这种查询就没有优化余地了吗?
非也。
下面就是一个简单的优化:
select id from kw_user where name = 'wallkop' AND password = '44209a6a592dea91bcf7d4dd53e47a5a' 时间: 0.060 s select id as user_id, name, nickname, photo, status, sdk_key, sdk_status from kw_user where id=37215 时间: 0.001 s 总耗时:0.061 s
将一条查询语句拆成两条,第一条不走索引的查询,我们尽量去简化它,只查一个id字段,你会惊奇的发现:速度居然提升了4倍。
而第二条查询用户详细信息的SQL,我们走了主键索引,仅仅用了0.001s。
如此一来,两条查询加起来总耗时才0.061s,比之前快了4倍。
这就是索引的灵活运用之道。
这里推荐一个查询SQL性能的利器:EXPLAIN
explain select * from kw_user_copy where new_id=1; explain select * from kw_user_copy where id=1;
可以自行试试explain对这两条SQL的解析差异在哪。
二.子查询(多表联查)优化
复杂查询中,子查询与多表联查非常普遍。
这些查询以SQL复杂、效率低下、维护困难等诸多特点著称,通常是程序猿和产品汪之间撕逼的导火索。
子查询速度慢的原因非常简单:
主查询遍历多少条数据,就要执行多少遍子查询。
简单来说,一张只有50条数据的表,普通