mysql join 和left join 对于索引的问题
今天遇到一个left join优化的问题,搞了一下午,中间查了不少资料,对MySQL的查询计划还有查询优化有了更进一步的了解,做一个简单的记录:
select c.* from hotel_info_original c
left join hotel_info_collection h
on c.hotel_type=h.hotel_type and c.hotel_id =h.hotel_id
where h.hotel_id is null
这个sql是用来查询出c表中有h表中无的记录,所以想到了用left join的特性(返回左边全部记录,右表不满足匹配条件的记录对应行返回null)来满足需求,不料这个查询非常慢。先来看查询计划: 
rows代表这个步骤相对上一步结果的每一行需要扫描的行数,可以看到这个sql需要扫描的行数为35773*8134,非常大的一个数字。本来c和h表的记录条数分别为40000+和10000+,这几乎是两个表做笛卡尔积的开销了(select * from c,h)。
于是我上网查了下MySQL实现join的原理,原来MySQL内部采用了一种叫做 nested loop join的算法。Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果还有第三个参与 Join,则再通过前两个表的 Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复,基本上MySQL采用的是最容易理解的算法来实现join。所以驱动表的选择非常重要,驱动表的数据小可以显著降低扫描的行数。
那么为什么一般情况下join的效率要高于left join很多?很多人说不明白原因,只人云亦云,我今天下午感悟出来了一点。一般情况下参与联合查询的两张表都会一大一小,如果是join,在没有其他过滤条件的情况下MySQL会选择小表作为驱动表,但是left join一般用作大表去join小表,而left join本身的特性决定了MySQL会用大表去做驱动表,这样下来效率就差了不少,如果我把上面那个sql改成
select c.* from hotel_info_original c
join hotel_info_collection h
on c.hotel_type=h.hotel_type and c.hotel_id =h.hotel_id
查询计划如下:
很明显,MySQL选择了小表作为驱动表,再配合(hotel_id,hotel_type)上的索引瞬间降低了好多个数量级。。。。。
另外,我今天还明白了一个关于left join 的通用法则,即:如果where条件中含有右表的非空条件(除开is null),则left join语句等同于join语句,可直接改写成join语句。
后记:
随着查看MySQL reference manual对这个问题进行了更进一步的了解。MySQL在执行join时会把join分为system/const/eq_ref/ref/range/index/ALl等好几类,连接的效率从前往后
依次递减,对于我的第一个sql,连接类型是index,所以几乎是全表扫描的效果。但是我很奇怪我在(hotel_id,hotel_type)两列上声明了unique key,根据官方文档连接类型应该是eq_ref才对,
这个问题一直困扰了我两天,在google和stackoverflow上都没有找到能够解释这个问题的文章,莫非我这个问题无解了?抱着解决这个问题的决心今天又翻看了一遍MySQL官方文档
关于优化查询的部分,看到了这样一句:这里的一个问题是MySQL能更高效地在声明具有相同类型和尺寸的列上使用索引。我感觉我找到了问题所在,于是我将original和 collection表的(hotel_type,hotel_id)的encoding和collation(决定字符比较的规则)全部改成统一的utf8_general_ci,然后再次运行第一条sql的查询计划,得到如下结果: 
连接类型已经由index优化到了ref,如果将hotel_type申明为not null可以优化到eq_ref,不过这里影响不大了,优化后这条sql能在0.01ms内运行完。
那么如何优化left join:
1、条件中尽量能够过滤一些行将驱动表变得小一点,用小表去驱动大表
2、右表的条件列一定要加上索引(主键、唯一索引、前缀索引等),最好能够使type达到range及以上(ref,eq_ref,const,system)
3、无视以上两点,一般不要用left join~~!
mysql join 和left join 对于索引的问题的更多相关文章
- MySql学习(三) —— 子查询(where、from、exists) 及 连接查询(left join、right join、inner join、union join)
注:该MySql系列博客仅为个人学习笔记. 同样的,使用goods表来练习子查询,表结构如下: 所有数据(cat_id与category.cat_id关联): 类别表: mingoods(连接查询时作 ...
- mysql 如何优化left join
今天遇到一个left join优化的问题,搞了一下午,中间查了不少资料,对MySQL的查询计划还有查询优化有了更进一步的了解,做一个简单的记录: select c.* from hotel_info_ ...
- MySQL基础之STRAIGHT JOIN用法简介
MySQL基础之STRAIGHT JOIN用法简介 引用mysql官方手册的说法: STRAIGHT_JOIN is similar to JOIN, except that the left tab ...
- Mysql查询优化器之关于JOIN的优化
连接查询应该是比较常用的查询方式,连接查询大致分为:内连接.外连接(左连接和右连接).自然连接 下图展示了 LEFT JOIN.RIGHT JOIN.INNER JOIN.OUTER JOIN 相关的 ...
- 【转】mysql的union、left join、 right join、 inner join和视图学习
1.联合 union 进行多个查询语句时,要求多次查询的结果列数必须一样.此时,查询的结果以第一个sql语句的列名为准且union会自动去重复我们应该使用union all. 例...... 1.联合 ...
- MySQL的几种连接 join/inner join/cross join/逗号/left join/right join/natural join
转载请注明出处!! 之前数据表连接操作多使用逗号或者join,对几种连接的概念一直浑浑噩噩,最近研究了一波,把这些连接的区别搞明白了. 连接:A xjoin B(主表 操作 关联表) selec ...
- mysql inner join,full outer join,left join,right jion
https://sites.google.com/site/349624yu/courses/mysql/mysqldbgjzcx inner join,full outer join,left jo ...
- MySQL的联结(Join)语法
MySQL的联结(Join)语法 1.内联结.外联结.左联结.右联结的含义及区别: 在讲MySQL的Join语法前还是先回顾一下联结的语法,呵呵,其实连我自己都忘得差不多了,那就大家一起温习吧(如 ...
- MySQL中Left Join和Right Join的理解
虽然之前一直见过两个Join,对于其具体的含义也在参考书上读过,但是一直没有记住.现在换一种方式进行学习,改为实验方式理解. Left Join 测试表: 表结构很简单,test包括两个int字段,t ...
随机推荐
- 用dubbo时遇到的一个序列化的坑
首先,这是标题党,问题并不是出现在序列化上,这是报错的一部分: Caused by: com.alibaba.dubbo.remoting.RemotingException: Failed to s ...
- nw.js桌面软件开发系列 第0.1节 HTML5和桌面软件开发的碰撞
第0.1节 HTML5和桌面软件开发的碰撞 当我们谈论桌面软件开发技术的时候,你会想到什么?如果不对技术本身进行更为深入的探讨,在我的世界里,有这么多技术概念可以被罗列出来(请原谅我本质上是一个Win ...
- dagger2系列之依赖方式dependencies、包含方式(从属方式)SubComponent
本篇是实战文章,从代码的角度分析这两种方式.本文参考自下列文章: http://www.jianshu.com/p/1d42d2e6f4a5 http://www.jianshu.com/p/94d4 ...
- 极光推送和友盟推送,ios端和安卓端的后端调试设置
我是最后端的,这两天搞了一个app项目,前端安卓使用友盟很方便,调试比较顺利,然后ios就遇到各种问题了,证书.发送成功推送不成功,测试时用的TestMode(),ios上架之后就必须用product ...
- iOS 后台处理
iOS 后台处理的常见用途 1.进入后台时候删除资源:应用处于挂起状态的时候所占用的资源越少,该应用被iOS终止的风险就越低.通过从内存中清理那些易于重新创建的资源,可以增加应用驻留内存的机会,因此可 ...
- 基于jQuery左右滑动切换特效 附源码
分享一款基于脚jQuery左右滑动切换特效.这是一款鼠标点击左右箭头按钮图片滚动切换,鼠标移到图片上显示透明边框特效. 效果图如下: 废话不多说,代码奉上! html代码: <div ...
- Jquery 获得当前标签的名称和标签属性
得到标签的名称 $("#name").prop("tagName"); 或者 $("#name")[0].tagName; 注意:1.得到的 ...
- [bzoj2152][聪聪和可可] (点分治+概率)
Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...
- 钉钉开放平台demo调试异常问题解决:hostname in certificate didn't match
今天研究钉钉的开放平台,结果一个demo整了半天,这帮助系统写的也很难懂.遇到两个问题: 1.首先是执行demo时报unable to find valid certification path to ...
- ola.hallengren的SQL Server维护脚本
ola.hallengren的SQL Server维护脚本 下载地址 http://files.cnblogs.com/files/lyhabc/ola.hallengrenMaintenanceSo ...