1)EXPLAIN
SELECT * FROM (
SELECT go_shoplist.title,
go_member.username
FROM go_shoplist
LEFT JOIN go_member ON go_shoplist.q_uid = go_member.uid
WHERE go_shoplist.sid IN (196,175,7064,1370,185,195,199,203)
AND go_shoplist.q_uid IS NOT NULL
ORDER BY id
) a
GROUP BY a.title ;
2)EXPLAIN
SELECT go_shoplist.title,
go_member.username
FROM go_shoplist
LEFT JOIN go_member ON go_shoplist.q_uid = go_member.uid
WHERE go_shoplist.id IN (
SELECT MAX(id) FROM go_shoplist
WHERE go_shoplist.sid IN (196,175,7064,1370,185,195,199,203)
AND go_shoplist.q_uid IS NOT NULL
GROUP BY sid
)
ORDER BY go_shoplist.id DESC;
为什么第二个更慢?
答: mysql 在处理子查询时,会改写子查询。
通常情况下,我们希望由内到外,先完成子查询的结果,然后再用子查询来驱动外查询的表,完成查询。
上一页的sql语句,通常我们会感性地认为该 sql 的执行顺序是:
go_shoplist 表中根据 sid in (…)取得 max(id)记录,
然后再到 go_shoplist中,带入 id in (…)取得查询数据。
但是实际mysql的处理方式为:
select * from go_shoplist … where exists (
select * from go_shoplist where sid in (…)
)
mysql 将会扫描 go_shoplist 中所有数据,每条数据都将会传到子查询中与 go_shoplist 关联,
子查询不会先被执行,所以如果 go_shoplist表很大的话,那么性能上将会出现问题。
3)还能继续优化吗?
答: SELECT a.id,b.title,d.username
FROM go_shoplist b
RIGHT JOIN (SELECT MAX(id) AS id FROM go_shoplist c
WHERE c.sid IN (196,175,7064,1370,185,195,199,203)
AND c.q_uid IS NOT NULL
GROUP BY c.sid ) a ON a.id = b.id
LEFT JOIN go_member d ON b.q_uid = d.uid
4)用explain看看好在哪了。
1)in 和 not in 要慎用(前面提到了)
2)应尽量避免在 where 子句中对字段进行表达式操作,
如:select id from t where num/2=100
应改为: select id from t where num=100*2
3)在使用索引字段作为条件时,如果该索引是复合索引,
那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,
否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致
4)索引并不是越多越好,索引固然可以提高相应的 select 的效率,
但同时也降低了 insert 及 update 的效率
5)不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的字段
6)尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写
7)尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理
8)能用UNION ALL就不要用UNION