转自博客http://huoding.com/2013/06/04/261

问题

通过「SHOW FULL PROCESSLIST」语句很容易就能查到问题SQL,如下:

SELECT post.*
FROM post
INNER JOIN post_tag ON post.id = post_tag.post_id
WHERE post.status = 1 AND post_tag.tag_id = 123
ORDER BY post.created DESC
LIMIT 100

说明:因为post和tag是多对多的关系,所以存在一个关联表post_tag。

试着用EXPLAIN查询一下SQL执行计划(篇幅所限,结果有删减):

+----------+---------+-------+-----------------------------+
| table | key | rows | Extra |
+----------+---------+-------+-----------------------------+
| post_tag | tag_id | 71220 | Using where; Using filesort |
| post | PRIMARY | 1 | Using where |
+----------+---------+-------+-----------------------------+

下面给出优化后的SQL,唯一的变化就是把连接方式改成了「STRAIGHT_JOIN」:

SELECT post.*
FROM post
STRAIGHT_JOIN post_tag ON post.id = post_tag.post_id
WHERE post.status = 1 AND post_tag.tag_id = 123
ORDER BY post.created DESC
LIMIT 100

试着用EXPLAIN查询一下SQL执行计划(篇幅所限,结果有删减):

+----------+----------------+--------+-------------+
| table | key | rows | Extra |
+----------+----------------+--------+-------------+
| post | status_created | 119340 | Using where |
| post_tag | post_id | 1 | Using where |
+----------+----------------+--------+-------------+

对比优化前后两次EXPLAIN的结果来看,优化后的SQL虽然「rows」更大了,但是没有了「Using filesort」,综合来看,性能依然得到了提升。

提醒:注意两次EXPLAIN结果中各个表出现的先后顺序,稍后会解释。

解释

对第一条SQL而言,为什么MySQL优化器选择了一个耗时的执行方案?对第二条SQL而言,为什么把连接方式改成STRAIGHT_JOIN之后就提升了性能?

这一切还得从MySQL对多表连接的处理方式说起,首先MySQL优化器要确定以谁为驱动表,也就是说以哪个表为基准,在处理此类问题时,MySQL优化器采用了简单粗暴的解决方法:哪个表的结果集小,就以哪个表为驱动表,当然MySQL优化器实际的处理方式会复杂许多,具体可以参考:MySQL优化器如何选择索引和JOIN顺序

说明:在EXPLAIN结果中,第一行出现的表就是驱动表。

继续post连接post_tag的例子,MySQL优化器有如下两个选择,分别是:

  • 以post为驱动表,通过status_created索引过滤,结果集119340行
  • 以post_tag为驱动表,通过tag_id索引过滤,结果集71220行

显而易见,post_tag过滤的结果集更小,所以MySQL优化器选择它作为驱动表,可悲催的是我们还需要以post表中的created字段来排序,也就是说排序字段不在驱动表里,于是乎不可避免的出现了「Using filesort」,甚至「Using temporary」。

知道了来龙去脉,优化起来就容易了,要尽可能的保证排序字段在驱动表中,所以必须以post为驱动表,于是乎必须借助「STRAIGHT_JOIN」强制连接顺序。

实际上在某些特殊情况里,排序字段可以不在驱动表里,比如驱动表结果集只有一行记录,并且在连接其它表时,索引除了连接字段,还包含了排序字段,此时连接表后,索引中的数据本身自然就是排好序的。

既然聊到这里顺带说点题外话,大家可能会遇到类似下面的问题:原本运行良好的查询语句,过了一段时间后,可能会突然变得很糟糕。一个很大可能的原因就是数据分布情况发生了变化,从而导致MySQL优化器对驱动表的选择发生了变化,进而出现索引失效的情况,所以没事最好多查查,关注一下这些情况。

对于「STRAIGHT_JOIN」,我总觉得这种非标准的语法属于奇技淫巧的范畴,能不用尽量不用,毕竟多数情况下,MySQL优化器都能做出正确的选择。

0111MySQL优化的奇技淫巧之STRAIGHT_JOIN的更多相关文章

  1. MySQL优化的奇技淫巧之STRAIGHT_JOIN

    原文地址:http://huoding.com/2013/06/04/261 问题 通过「SHOW FULL PROCESSLIST」语句很容易就能查到问题SQL,如下: SELECT post.* ...

  2. [慢查优化]联表查询注意谁是驱动表 & 你搞不清楚谁join谁更好时请放手让mysql自行判定

    写在前面的话: 不要求每个人一定理解 联表查询(join/left join/inner join等)时的mysql运算过程: 不要求每个人一定知道线上(现在或未来)哪张表数据量大,哪张表数据量小: ...

  3. 【转】[慢查优化]联表查询注意谁是驱动表 & 你搞不清楚谁join谁更好时请放手让mysql自行判定

    转自:http://zhengyun-ustc.iteye.com/blog/1942797 写在前面的话: 不要求每个人一定理解 联表查询(join/left join/inner join等)时的 ...

  4. 浅谈SQL优化入门:2、等值连接和EXPLAIN(MySQL)

    1.等值连接:显性连接和隐性连接 在<MySQL必知必会>中对于等值连接有提到两种方式,第一种是直接在WHERE子句中规定如何关联即可,那么第二种则是使用INNER JOIN关键字.如下例 ...

  5. (转)MySQL join语法解析与性能分析

    文章转载的:http://www.cnblogs.com/BeginMan/p/3754322.html 一.join语法概述 join用于多表中字段之间的联系,语法如下: ... FROM tabl ...

  6. mysql的join操作

    一.Join语法概述 join 用于多表中字段之间的联系,语法如下: ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona table1 ...

  7. [转]Mysql Join语法解析与性能分析

    转自:http://www.cnblogs.com/BeginMan/p/3754322.html 一.Join语法概述 join 用于多表中字段之间的联系,语法如下: ... FROM table1 ...

  8. Java并发编程常识

    这是why的第 85 篇原创文章 写中间件经常要做两件事: 1.延迟加载,在内存缓存已加载项. 2.统计调用次数,拦截并发量. 就这么个小功能,团队里的人十有八九写错. 上面这句话不是我说的,是梁飞在 ...

  9. MySQL性能优化奇技淫巧

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引.   2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使 ...

随机推荐

  1. Flex布局 Flexbox属性具体解释

    原文:A Visual Guide to CSS3 Flexbox Properties Flex布局官方称为CSS Flexble Box布局模型是CSS3为了提高元素在容器中的对齐.方向.顺序,甚 ...

  2. 错误: su: 无法设置组: 不允许的操作

    到 /bin目录下,用ls -l 看下su文件的权限是不是rwxr-xr-x或者-rwxrwxrwx 执行这条命令chmod ug+s su

  3. oc10--练习

    // // main.m // 练习 #import <Foundation/Foundation.h> @interface Car : NSObject { @public int w ...

  4. 分享3个Putty配色方案【转】

    本文转载自:https://www.coder4.com/archives/1506 分享3个Putty配色方案 4 Replies 虽然服务器都是Linux的,平时也基本用Linux,但是难免还是要 ...

  5. 利用Powershell和ceye.io实现Windows账户密码回传

    利用Powershell和ceye.io实现Windows账户密码回传 转自:http://www.freebuf.com/articles/system/129068.html 最近在研究Power ...

  6. poj 2031--Building a Space Station(prim)

    Building a Space Station Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 6064   Accepte ...

  7. mysql在第一次查询的时候很慢,第二次查询就比较快的原因?

    1.默认 query_cache 是打开的 你使用 show global variables like '%query_cache%'; 确认一下有没有打开,如果打开了.第一次查询读数据文件,第二次 ...

  8. 第6章 服务模式 Service Interface(服务接口)

    Service Interface(服务接口) 上下文 您正在设计企业应用程序,并且需要能够通过网络使用其部分功能.此功能需要能够被各类系统使用,因此互操作性是设计的重要方面.除互操作性之外,可能还需 ...

  9. 初学 Ajax(涉及 php)

    一直知道 ajax 但是尚未真正了解, 这次看了慕课网的<Ajax全接触>,算是有所收获,入了个门. 需要用到php,因为 Ajax也是向服务器请求(不知道这么解释对不对), 所以还需要配 ...

  10. (转)webpack从零开始第6课:在Vue开发中使用webpack

    vue官方已经写好一个vue-webpack模板vue_cli,原本自己写一个,发现官方写得已经够好了,自己写显得有点多余,但为了让大家熟悉webpack,决定还是一步一步从0开始写,但源文件就直接拷 ...