问题

最近在调试一条查询耗时5s多的sql语句,这条sql语句用到了多表关联(inner join),按时间字段排序(order by),时间字段上已经创建了索引(索引名IDX_published_at)。通过explain分析发现,时间字段上的索引没用上(Using temporary和Using filesort),问题很明显,但是原因是什么呢?

SELECT * FROM news n0_ inner join news_translations n1_ ON n0_.id = n1_.translatable_id inner join channels_news c3_ ON n0_.id = c3_.news_id
WHERE
((n0_.unpublished_at IS NOT NULL AND (CURRENT_TIMESTAMP >= n0_.published_at AND CURRENT_TIMESTAMP < n0_.unpublished_at)) OR (CURRENT_TIMESTAMP >= n0_.published_at AND n0_.unpublished_at IS NULL))
AND (n0_.status = 1 AND n0_.content_type_id = 1) AND n0_.id NOT IN (510466, 510433, 24, 11, 10, 9, 4)
AND n0_.home_position_id IS NULL
AND
n1_.locale = 'zh_CN'
AND
c3_.channel_id = 1
ORDER BY n0_.published_at DESC
LIMIT 5 ;

优化前sql语句

+-------+--------+-------------------------------+--------+-----------------------------------------------------------+
| table | type | key | rows | Extra |
+-------+--------+-------------------------------+--------+-----------------------------------------------------------+
| c3_ | ref | IDX_87B9249E72F5A1AA | 161590 | Using where; Using index; Using temporary; Using filesort |
| n0_ | eq_ref | PRIMARY | 1 | Using where |
| n1_ | ref | UNIQ_20FDB3302C2AC5D34180C698 | 1 | Using where |
+-------+--------+-------------------------------+--------+-----------------------------------------------------------+

explain分析结果 有所删减

经过一轮折腾的优化,得到了下面的sql语句

SELECT * FROM news n0_ STRAIGHT_JOIN news_translations n1_ ON n0_.id = n1_.translatable_id STRAIGHT_JOIN channels_news c3_ ON n0_.id = c3_.news_id
WHERE
((n0_.unpublished_at IS NOT NULL AND (CURRENT_TIMESTAMP >= n0_.published_at AND CURRENT_TIMESTAMP < n0_.unpublished_at)) OR (CURRENT_TIMESTAMP >= n0_.published_at AND n0_.unpublished_at IS NULL))
AND (n0_.status = 1 AND n0_.content_type_id = 1) AND n0_.id NOT IN (510466, 510433, 24, 11, 10, 9, 4)
AND n0_.home_position_id IS NULL
AND
n1_.locale = 'zh_CN'
AND
c3_.channel_id = 1
ORDER BY n0_.published_at DESC
LIMIT 5 ;

优化后sql语句

+-------+--------+-------------------------------+--------+--------------------------+
| table | type | key | rows | Extra |
+-------+--------+-------------------------------+--------+--------------------------+
| n0_ | range | IDX_published_at | 255440 | Using where |
| n1_ | ref | UNIQ_20FDB3302C2AC5D34180C698 | 1 | Using where |
| c3_ | eq_ref | PRIMARY | 1 | Using where; Using index |
+-------+--------+-------------------------------+--------+--------------------------+

优化后explain分析结果 有所删减

优化前后的变化有四点:1、不再Using temporary和Using filesort;2、表的查询顺寻变了;3、查询扫描的rows增加了;4、查询时间由5s降到了0.02s。

原因分析

优化前后出现的四点变化,性能显著提升,需要从mysql的关联的连接处理说起。

以下参考《高性能MySQL》

1)优化前的sql语句以channels_news为第一个关联表,找到161590条记录;2)优化后的sql语句以news表为第一关联表,找到255440条记录,比第一条sql语句查找多了9W多条。因此,优化前的sql语句的关联顺序是MySQL优化器的选择,可以让查询进行更小的嵌套循环和回溯操作。MySQL通过选择合适的关联顺序来让查询执行的成本尽可能低,重新定义关联的顺序是优化器很重要的一部分功能。不过有时候,优化器给出的并不是最优的关联顺序。这时可以使用STRAIGHT_JOIN关键字重写查询,让优化器按照你认为的最优关联顺序执行。

从优化后的explain分析结果看出,news是驱动表,结果以news表的published_at字段进行排序,所以用上了索引,避免了Using temporary和Using filesort,自然而然的,查询时间也降下来了。正如前面说的,mysql的优化器通过粗暴的小表驱动大表来选择连接的顺序,第一条sql语句扫描了161590行,第二条sql语句扫描了255440行,优化后的sql语句扫描的行数增加了。

结语

结案陈词:造成这次sql语句查询耗时5s的原因是,sql语句order by的字段不在mysql的优化器选在驱动表上,所以导致这次关联查询排序字段上的索引没有被使用。因此,通过使用STRAIGHT_JOIN来强制制定关联查询的表顺序,以达到优化的目的。但是,有时候我们人为地指定顺序不一定比mysql的优化引擎准确,所以在使用STRAIGHT_JOIN的时候三思而后行。

本文链接:http://www.hcoding.com/?p=211

原创文章,转载请注明:JC&hcoding.com

书愤

陆游

早岁那知世事艰,中原北望气如山。

楼船夜雪瓜洲渡,铁马秋风大散关。

塞上长城空自许,镜中衰鬓已先斑。

出师一表真名世,千载谁堪伯仲间。

MySQL STRAIGHT_JOIN的更多相关文章

  1. Mysql 多表查询

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

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

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

  3. mysql的join操作

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

  4. mysql 关于join的总结

    本文地址:http://www.cnblogs.com/qiaoyihang/p/6401280.html mysql不支持Full join,不过可以通过UNION 关键字来合并 LEFT JOIN ...

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

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

  6. MySQL- -Join语法解析与性能分析

    Mysql Join语法解析与性能分析 一.Join语法概述 join 用于多表中字段之间的联系,语法如下: ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ...

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

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

  8. MySQL HINT:Straight_JOIN

    来自生产环境的朋友.可能都会碰到:          原本运行良好的查询语句,过了一段时间后,可能会突然变得很糟糕     一个很大可能的原因就是数据分布情况发生了变化     从而导致MySQL优化 ...

  9. 20170103简单解析MySQL查询优化器工作原理

    转自博客http://www.cnblogs.com/hellohell/p/5718238.html 感谢楼主的贡献 查询优化器的任务是发现执行SQL查询的最佳方案.大多数查询优化器,包括MySQL ...

随机推荐

  1. 转:Spine.JS+Rails重客户端Web应用技术选型思路:『风车』架构设计

    原文来自于:http://www.infoq.com/cn/articles/fengche-co-architecture 风车这个项目开始于 2011 年 11 月份,之前叫做 Pragmatic ...

  2. reg51.h 详解

    /* BYTE Register */ sfr P0 = 0x80; //P0口 sfr P1 = 0x90; //P1口 sfr P2 = 0xA0; //P2口 sfr P3 = 0xB0; // ...

  3. 天底下最简单的QT画图板,就一个类,60行代码

    简单直观.但是我有个问题是,这实际上不是在绘制直线,而是几千几万个超级短的“直线”,这样会不会效率很低呢? 注意,每次绘制的时候,需要一支笔,这支笔需要设置颜色和宽度(就像我们平时写字也要稍微挑一下笔 ...

  4. ASCII、Unicode、GBK和UTF-8字符编码的区别联系[转]

    http://dengo.org/archives/901 这是我看过的最好的一篇讲述编码的文章 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物.他们看到 ...

  5. Qt入门(2)——使用Qt编写的Hello world

    对于一个qt初学者来说,一步一步来直到作出一个hello world是最基础的入门. 从菜单:应用程序->编程中找到QtCreator

  6. 从windows server 2003中学到的事儿

    2003让我学会了几件事儿, 第一.自己会装系统了. 第二.知道很多选项是可以自己进行设置的.这点很重要,本来xp用得很习惯,然后很多都理所当然得认为,就应该是那个样子,可是,并不是的. 在2003不 ...

  7. 删除WIN7系统的共享文件

    运行里面输入fsmgmt.msc命令,点开共享目录,选定要取消共享的文件右键,停止共享.

  8. Android新浪微博客户端(一)——主框架搭建

    原文出自:方杰| http://fangjie.info/?p=62 转载请注明出处 提前声明的是,我是按照Ivan的这套教程学下来的. 首先,对于任何应用我们都需要建立一套消息处理机制,就是当用户在 ...

  9. HDU_1238——最大子串搜索

    Problem Description You are given a number of case-sensitive strings of alphabetic characters, find ...

  10. BeanstalkClient学习

    针对BeanstalkClient-1.4.6.jar 生产者 示例代码: package com.lky.test; import java.io.UnsupportedEncodingExcept ...