今天遇到一个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 对于索引的问题的更多相关文章

  1. MySql学习(三) —— 子查询(where、from、exists) 及 连接查询(left join、right join、inner join、union join)

    注:该MySql系列博客仅为个人学习笔记. 同样的,使用goods表来练习子查询,表结构如下: 所有数据(cat_id与category.cat_id关联): 类别表: mingoods(连接查询时作 ...

  2. mysql 如何优化left join

    今天遇到一个left join优化的问题,搞了一下午,中间查了不少资料,对MySQL的查询计划还有查询优化有了更进一步的了解,做一个简单的记录: select c.* from hotel_info_ ...

  3. MySQL基础之STRAIGHT JOIN用法简介

    MySQL基础之STRAIGHT JOIN用法简介 引用mysql官方手册的说法: STRAIGHT_JOIN is similar to JOIN, except that the left tab ...

  4. Mysql查询优化器之关于JOIN的优化

    连接查询应该是比较常用的查询方式,连接查询大致分为:内连接.外连接(左连接和右连接).自然连接 下图展示了 LEFT JOIN.RIGHT JOIN.INNER JOIN.OUTER JOIN 相关的 ...

  5. 【转】mysql的union、left join、 right join、 inner join和视图学习

    1.联合 union 进行多个查询语句时,要求多次查询的结果列数必须一样.此时,查询的结果以第一个sql语句的列名为准且union会自动去重复我们应该使用union all. 例...... 1.联合 ...

  6. MySQL的几种连接 join/inner join/cross join/逗号/left join/right join/natural join

    转载请注明出处!! 之前数据表连接操作多使用逗号或者join,对几种连接的概念一直浑浑噩噩,最近研究了一波,把这些连接的区别搞明白了.   连接:A xjoin B(主表 操作 关联表)  selec ...

  7. 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 ...

  8. MySQL的联结(Join)语法

    MySQL的联结(Join)语法 1.内联结.外联结.左联结.右联结的含义及区别:   在讲MySQL的Join语法前还是先回顾一下联结的语法,呵呵,其实连我自己都忘得差不多了,那就大家一起温习吧(如 ...

  9. MySQL中Left Join和Right Join的理解

    虽然之前一直见过两个Join,对于其具体的含义也在参考书上读过,但是一直没有记住.现在换一种方式进行学习,改为实验方式理解. Left Join 测试表: 表结构很简单,test包括两个int字段,t ...

随机推荐

  1. 基于本地存储的kvm虚拟机在线迁移

    基于本地存储的kvm虚拟机在线迁移 kvm虚拟机迁移分为4种(1)热迁移基于共享存储(2)热迁移基于本地存储(3)冷迁移基于共享存储(4)冷迁移基于本地存储 这里介绍的是基于本地存储的热迁移 动态块迁 ...

  2. CoreCRM 开发实录——想用国货不容易

    昨天(2016年12月29日)发了开始开发的文章.本来晚上准备在 Coding.NET 上添加几个任务开始搞起了.可是真的开始用的时候才发现:Coding.NET 的任务功能只针对私有的任务开放.我想 ...

  3. 展望未来:使用 PostCSS 和 cssnext 书写 CSS

    原文链接:A look into writing future CSS with PostCSS and cssnext 译者:nzbin 像twitter,google,bbc使用的一样,我打算看一 ...

  4. Hawk 4.4 执行器

    执行器是负责将Hawk的结果传送到外部环境的工具.你可以写入数据表,数据库,甚至执行某个特定的动作,或是生成文件等等. 在调试模式下,执行器都是不工作的.这是为了避免产生副作用.否则,每刷新一遍数据, ...

  5. vs2010静态链接MFC库报链接错误

    由于需要将MFC程序在其它电脑上运行,所以需要将动态链接的MFC改成静态链接,本以为很简单,没想到链接的时候出现下面的链接错误: uafxcw.lib(afxmem.obj) : error LNK2 ...

  6. 通过VMware的PowerCLI配置集群内指定主机的vMotion功能

    PowerCLI是VMware开发的基于微软(MSFT)的PowerShell的命令行管理vSphere的实现,因此在批量化操作方面CLI会减轻很多GUI环境下的繁琐重复劳作. 现有场景中有大量的物理 ...

  7. 代码的坏味道(17)——夸夸其谈未来性(Speculative Generality)

    坏味道--夸夸其谈未来性(Speculative Generality) 特征 存在未被使用的类.函数.字段或参数. 问题原因 有时,代码仅仅为了支持未来的特性而产生,然而却一直未实现.结果,代码变得 ...

  8. MATLAB中绘制质点轨迹动图并保存成GIF

    工作需要在MATLAB中绘制质点轨迹并保存成GIF以便展示. 绘制质点轨迹动图可用comet和comet3命令,使用例子如下: t = 0:.01:2*pi;x = cos(2*t).*(cos(t) ...

  9. HTTP API接口安全设计

    HTTP API接口安全设计 API接口调用方式 HTTP + 请求签名机制   HTTP + 参数签名机制 HTTPS + 访问令牌机制 有没有更好的方案? OAuth授权机制 OAuth2.0服务 ...

  10. Oracle-BPM安装详解

    H3 BPM安装包括两个部分,基础工作包括安装IIS..net Freamwork基础框架.安装完成之后,主要配置安装包括数据库,H3 BPM 程序.下面详细介绍Oracle与H3 BPM对接安装的整 ...