给出两个表,A和B,A和B表的数据量,

当A小于B时,用exists
select * from A where exists (select * from B where A.id=B.id)
exists的实现,相当于外表循环,每次循环对内表进行查询?
for i in A
for j in B
if j.id == i.id then ....
相反,如果A大于B的时候,则用in
select * from A where id in (select id from B)
这种在逻辑上类似于
for i in B
for j in A
if j.id == i.id then ....
然后MySQL实现in,使用了hash join (哈希连接)。我猜想和逻辑上的两层循环在工作原理上是不一样的。
 
经过我的实际测试
SELECT * FROM user u where exists  (SELECT 0 FROM plan p where p.user_id=u.user_id )
0.188 sec / 6.234 sec
 
SELECT * FROM user u where  user_id in  (SELECT user_id FROM plan)
0.015 sec / 0.000 sec
使用in的可谓是瞬间的
 
其中Plan表有3300行记录,User表有3800,数据量恰好接近。
所以那个伪码(两层循环只能帮助理解),和实际情况差距很大。否则二者应该非常接近才对。
 
  Duration Fetch Rows  SQL
exists 0.17 6.2 924 SELECT * FROM user u where exists  (SELECT 0 FROM plan p where p.user_id=u.user_id )
in 0.01 0.0 924 SELECT * FROM user u where  user_id in  (SELECT user_id FROM plan)
 虽然数据量很小,但是可以想象,如果我们用exists,可能会非常糟糕,难怪都建议用in。
 
 
Hash Join
1. 什么事Hash Join。据说是Oracle7.3以后出现的一种连接技术,估计就是要解决本质形如两层循环的工作方式吧(猜测)
那么,select * from A where id in (select id from B),我猜测实际处理中,会变为。
dict = hash(B)
for i in A
if i in dict then ...

如果如此,当然会快很多了。并且之前提到过,B表小的时候,用in,在这里也正好被放到一个Hash表里面。

更多引用:
1、hash join 就是哈希连接,当一个表或多个表上没有索引时,或者数据库服务器必须从所有连接表读取大量行的时候,就用这种方法。
2、orcale7.3以后才出来一种hash join的新的连接技术,hash join只能用于相等连接。
3、相对于以前的nested loop join连接技术,hash join更适合处理大型结果集,而且不需要在驱动表上建索引。
4、hash算法就是在两个表连接的时候,首先要区分大表和小表,小表用S来表示,大表用B来表示,然后就把小表S表放在一个内存的hash table中。
5、若这个小表S表还是太大,放不进去hash table中,就应该对这个hash table要分区,对于大表B表也是要放在内存中的,若B表也是太大,那也要进行分区处理。
6、这样的话,S表就分开若干个区,B表也分成若干个区,这样就开始各个分区之间的互连。
7、除了hash table的分区后,还有一个就是hash area内存的感念,就是逐个处理S与B的各个子集相连情况,首先把小表放在内存里,内存是高速缓冲区,速度快,大表放在慢速的存储区内,从慢速区内读条数据后,再与高速区的做循环,这样肯定会很快的,反过来就慢了,所以优化始终强调小表套大表,小表在高速缓冲区内执行,大表在慢速区放着。
8、S与B的两两相连时,会出现脚色互换的的,当B表的某个分区少的话,那这个小B表进如hash area中做主表。
9、hash join的核心就是确认小表为驱动表,在算法执行之前大小表都要拆分,会有两者角色互换的情况,关键是看谁的数量小,小的进高速内存跑循环,大的在外面有IO处理过程。
10、总之hash join适合于小表与大表相连,返回大型结果集的连接。

从这里摘的:http://blog.sina.com.cn/s/blog_648760e30101b1uh.html

 
Not in
1. 不要使用Not in,解决办法无外乎加索引,这样会快一些,然后效果未必明显,一般是改用Left join。
select * from A where id in (select id from B)
===>
select * from A left join B on a.id=b.id where b.id is null
 
关键是为什么in很快,not in很慢,
首先,not in并非是我们想象中的那样,subquery只求一次值,然后外层select判断是否in这个集合。
事实上,subquery会被执行N次。(好吧,疯了吧,然而我没有想清楚,为什么不能(设计成)执行一次就OK了。)
参考:https://stackoverflow.com/questions/12728654/why-is-this-mysql-query-with-the-not-in-statement-so-slow/12728981#12728981
 
 

小表驱动大表, 兼论exists和in的更多相关文章

  1. 查询优化--小表驱动大表(In,Exists区别)

    Mysql 系列文章主页 =============== 本文将以真实例子来讲解小表驱动大表(In,Exists区别) 1 准备数据 1.1 创建表.函数.存储过程 参照  这篇(调用函数和存储过程批 ...

  2. 6.2 小表驱动大表(exists的应用)

    1. 优化原则:小表驱动大表,即小数据集驱动大数据集. select * from A where id in (select id from B) 等价于: for select id from B ...

  3. Mysql优化原则_小表驱动大表IN和EXISTS的合理利用

    //假设一个for循环 ; $i < ; $i++) { ; $i < ; $j++) { } } ; $i < ; $i++) { ; $i < ; $j++) { } } ...

  4. MySQL高级知识(十六)——小表驱动大表

    前言:本来小表驱动大表的知识应该在前面就讲解的,但是由于之前并没有学习数据批量插入,因此将其放在这里.在查询的优化中永远小表驱动大表. 1.为什么要小表驱动大表呢 类似循环嵌套 for(int i=5 ...

  5. MySql 小表驱动大表

    在了解之前要先了解对应语法 in 与 exist. IN: select * from A where A.id in (select B.id from B) in后的括号的表达式结果要求之输出一列 ...

  6. 了解MySQL联表查询中的驱动表,优化查询,以小表驱动大表

    一.为什么要用小表驱动大表 1.驱动表的定义 当进行多表连接查询时, [驱动表] 的定义为: 1)指定了联接条件时,满足查询条件的记录行数少的表为[驱动表] 2)未指定联接条件时,行数少的表为[驱动表 ...

  7. 3.mysql小表驱动大表的4种表连接算法

    小表驱动大表 1.概念 驱动表的概念是指多表关联查询时,第一个被处理的表,使用此表的记录去关联其他表.驱动表的确定很关键,会直接影响多表连接的关联顺序,也决定了后续关联时的查询性能. 2.原则 驱动表 ...

  8. 【Spark调优】小表join大表数据倾斜解决方案

    [使用场景] 对RDD使用join类操作,或者是在Spark SQL中使用join语句时,而且join操作中的一个RDD或表的数据量比较小(例如几百MB或者1~2GB),比较适用此方案. [解决方案] ...

  9. hive join 优化 --小表join大表

    1.小.大表 join 在小表和大表进行join时,将小表放在前边,效率会高.hive会将小表进行缓存. 2.mapjoin 使用mapjoin将小表放入内存,在map端和大表逐一匹配.从而省去red ...

随机推荐

  1. php大力力 [047节] 寻找程序员的方法和应用

    http://www.proginn.com 程序员客栈 程序员客栈是什么? 程序员客栈,程序员的经纪人.第一阶段,我们通过履历.作品.专业社区影响力.技能树帮助程序员立体地展现成就和价值,不被简历束 ...

  2. What is the DD in java web application

    http://docs.oracle.com/cd/E13222_01/wls/docs70/webapp/webappdeployment.html

  3. Linux装无线驱动

  4. 10大白帽黑客专用的 Linux 操作系统

    原文出处: Irshad Pathoor   译文出处:Linux中国   欢迎分享原创到伯乐头条 今天让我们来介绍十个黑客专用的操作系统,它们被白帽黑客用作渗透测试的工具.这里我把 Kali Lin ...

  5. HTML5+CSS3学习小记

    1.用网络图片作为背景图片: body{ background-image: url(http://b.hiphotos.baidu.com/album/h%3D900%3Bcrop%3D0%2C0% ...

  6. python小细节

    1.tab缩进2.读取文件,在文件名前加r或者R.这是因为python原始字符串特性,即在字符串的前面已R或者小写字母r开始,则字符串不对\进行转移,直接输出,通常用于表示windows的路径.fil ...

  7. 项目中创建单元测试—VS2012

    我们在每个项目的开发过程中,开发完一个功能,自己首先需要测试一下,VS提供了很方便的测试功能,可以很容易的创建单元测试,但是在VS2012中类名上点击右键没有『创建单元测试』这个菜单,需要先进行设置一 ...

  8. WebView返回时设置Title

    private TextView mWebTitle; private com.tencent.smtt.sdk.WebView mX5Web; ......... if (mX5Web.canGoB ...

  9. Hibernate save, saveOrUpdate, persist, merge, update 区别

    Hibernate Save hibernate save()方法能够保存实体到数据库,正如方法名称save这个单词所表明的意思.我们能够在事务之外调用这个方法,这也是我不喜欢使用这个方法保存数据的原 ...

  10. Spike Notes on Lock based Concurrency Concepts

    Motivation 承并发编程笔记Outline,这篇文章专注于记录学习基于锁的并发概念的过程中出现的一些知识点,为并发高层抽象做必要的准备. 尽管存在Doug Lee开山之作Concurrent ...