总的来说,left join的性能优化(尤其还涉及到排序)是个比较复杂、系统的问题,涉及到
驱动表
索引
的内在实现,仅能在以下三的有所关注:
1. 连接字段编码一致 悲剧:https://www.cnblogs.com/jarjune/articles/7912722.html
2. 认清主表作相应的优化,比如索引、排序之类的
3. 尽量用inner join
mysql join 和left join 对于索引的问题
MySQL内部采用了一种叫做 nested loop join的算法。Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。
那么为什么一般情况下join的效率要高于left join很多?一般情况下参与联合查询的两张表都会一大一小,如果是join,在没有其他过滤条件的情况下MySQL会选择小表作为驱动表,但是left join一般用作大表去join小表,而left join本身的特性决定了MySQL会用大表去做驱动表,这样下来效率就差了不少
我验证了一下
no index
user_id index
了解MySQL联表查询中的驱动表,优化查询,以小表驱动大表
http://blog.csdn.net/dc2222333/article/details/78234649
left join不变,干嘛要根据非驱动表的字段排序呢?我们前面说过“对驱动表可以直接排序,对非驱动表(的字段排序)需要对循环查询的合并结果(临时表)进行排序!”的。
MySQL中LEFT JOIN的主表
http://ourmysql.com/archives/775
EXPLAIN SELECT *
FROM posts
LEFT JOIN categories ON posts.category_id = categories.id
WHERE categories.id = ‘一个已经存在的ID’
ORDER BY posts.created DESC
结果如下所示:
table key Extra
categories PRIMARY Using filesort
posts category_id Using where
在explain的结果中,第一行表示的表就是主表,所以说在此查询里categories是主表,而在我们的经验里,LEFT JOIN查询里,左表(posts表)才应该是主表,这产生一个根本的矛盾,MySQL之所以这样处理,是因为在我们的WHERE部分,查询条件是按照categories表的字段来进行筛选的,而恰恰categories表存在合适的索引,所以在查询时把categories表作为主表更有利于缩小结果集。
那explain结果中的Using filesort又是为什么呢?这是因为主表是categories表,从表是posts表,而我们使用从表的字段去ORDER BY,这通常不是一个好选择,最好改成主表字段,如果鉴于需求所限,无法改成主表的字段,那么可以尝试添加如下索引:
ALTER TABLE `posts` ADD INDEX ( `category_id` , `created` );
再运行SQL时就不会有Using filesort了,这是因为主表categories在通过category_id连接从表posts时,可以进而通过索引直接得到排序后的posts结果。(这个我没验证出来)
主观上一旦搞错了主表,可能怎么调整索引都得不到高效的SQL,所以在写SQL时,比如说在写LEFT JOIN查询时,如果希望左表是主表,那么就要保证在WHERE语句里的查询条件尽可能多的使用左表字段,进而,一旦确定了主表,也最好只通过主表字段去ORDER BY。