大神级回答exists与in的区别
google搜了一下,很多帖子,而且出发点不同,各有各的道理,但是有一个帖子讲的特别好:
http://zhidao.baidu.com/question/134174568.html
忍不住在百度上回复了一下,怒赞,没想到别人早就回复过了:围观大神级回答。确实名副其实!
================in和exists=============================
in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询。
如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in:
例如:表A(小表),表B(大表)
1:select * from A where cc in (select cc from B) 效率低,用到了A表上cc列的索引;
select * from A where exists(select cc from B where cc=A.cc) 效率高,用到了B表上cc列的索引。
相反的2:
select * from B where cc in (select cc from A) 效率高,用到了B表上cc列的索引;
select * from B where exists(select cc from A where cc=B.cc) 效率低,用到了A表上cc列的索引。
not in 和not exists如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快。
------------------------我的评论-----------------------------------------
1本质上是要利用索引,2要区分大表小表,3not exists子查询能使用索引,速度更快。我的真实SQL是这样的:
INSERT INTO journal_curr
SELECT '2008-10-01' AS date_imp, act_numero, act_sexe, titre, act_nom, act_nom_abrege, act_sous_titre,act_adr_numero,act_adr_rue,
ltrim(concat( IFNULL(act_adr_numero,''),' ',act_adr_rue)) AS act_adr,act_adr_complement,act_cp,LEFT(act_cp,2) AS region,act_ville,act_pays, nb_exempl
FROM journal_abonn INNER JOIN actif
ON (journal_abonn.ref_client = actif.act_numero)
AND (ref_journal='NOUVEURO')
AND (act_pays<>'ALLEMAGNE')
AND ( ((date_abonn<='2008-10-01') AND (date_fin_abonn>='2008-10-01') AND (date_abonn_fin_envoi IS NULL))
OR ((date_abonn<='2008-10-01') AND (date_abonn_fin_envoi>='2008-10-01'))
OR ((act_type_abonne=4) AND ((date_fin_abonn>='2008-10-01') AND (date_abonn_fin_envoi IS NULL)))
OR ((act_type_abonne=4) AND (date_fin_abonn IS NULL) AND (date_abonn_fin_envoi IS NULL))
OR ((act_type_abonne=4) AND ((date_abonn_fin_envoi>='2008-10-01')))
)
AND (ref_abonn_new NOT IN (SELECT ref_abonn_new FROM journal_suspension
WHERE (debut_suspension<='2008-10-01')
AND (fin_suspension>='2008-10-01')
AND (ref_journal='NOUVEURO')
)
)
自从给journal_abonn加了ref_client加了索引以后,时间从30分钟下降到几秒(注意,我没给ref_abonn_new加索引)。
有趣的是,我这个例子刚好journal_abonn是大表,journal_suspension是小表,符合IN的使用条件。
大表真正使用的关键索引是ref_client,而不是ref_abonn_new,所以可以充分利用上。
小表计算速度无所谓,而且根据研究小表应该也是一次计算完后放在内存中。
另外,我这里是NOT IN,但是速度仍然很快,说明仍然利用上了索引,难道大神级回复也有小错?
================================================================
另外,我重新整理一下所有我搜到的发言,都很有道理:
通过使用exist,oracle系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间(我的评论,主表小当然应该先过滤主查询)。oracle系统在执行in子查询时,首先执行子查询(我的评论,从表小当然应该先过滤子查询),并将获得的结果列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用exists比使用in通常查询速度快的原因。
下面是一个非关联子查询:
select staff_name from staff_member where staff_id
in (select staff_id from staff_func);
而下面是一个关联子查询:
select staff_name from staff_member where staff_id in (select staff_id from staff_func where staff_member.staff_id=staff_func.staff_id);
以上返回的结果集是相同的,可是它们的执行开销是不同的:
非关联查询的开销——非关联查询时子查询只会执行一次,而且结果是排序好的,并保存在一个ORACLE的临时段中,其中的每一个记录在返回时都会被父查询所引用。在子查询返回大量的记录的情况下,将这些结果集排序,以及将临时数据段进行排序会增加大量的系统开销。
关联查询的开销——对返回到父查询的的记录来说,子查询会每行执行一次。因此,我们必须保证任何可能的时候子查询用到索引。
楼上说法片面,in和exist,各有快的时候,主要是看你的筛选条件是在主查询上还是在子查询上。
下面是oracle文档,:)
In certain circumstances, it is better to use IN rather than EXISTS. In general, if the selective predicate is in the subquery, then use IN. If the selective predicate is in the parent query, then use EXISTS.
Sometimes, Oracle can rewrite a subquery when used with an IN clause to take advantage of selectivity specified in the subquery. This is most beneficial when the most selective filter appears in the subquery and there are indexes on the join columns. Conversely, using EXISTS is beneficial when the most selective filter is in the parent query. This allows the selective predicates in the parent query to be applied before filtering the rows against the EXISTS criteria.
exists不需要记录,当存在的时候就返回。
用exists只检查行的存在性,而in检查到行里的实际的值。
参考:
http://bbs.csdn.net/topics/190124638
http://blog.csdn.net/lick4050312/article/details/4476333
A,B两个表
当只显示一个表的数据如A,关系条件只一个如ID时,使用IN更快:select * from A where id in (select id from B)
当只显示一个表的数据如A,关系条件不只一个如ID,col1时,使用IN就不方便了,可以使用EXISTS:select * from A where exists (select 1 from B where id = A.id and col1 = A.col1)
当只显示两个表的数据时,使用IN,EXISTS都不合适,要使用连接:select * from A left join B on id = A.id
参考:
http://www.cnblogs.com/AllUserBegin/p/3513084.html
大神级回答exists与in的区别的更多相关文章
- 为什么学习python?(知乎大神的回答)
学习PHP 是因为得到一份工作 学习Java 是因为他们选修了计算机科学这门课程 学习python 是因为爱这门语言,因为寻求美
- 知乎大神对IAAS,SAAS,PAAS区别的理解
你一定听说过云计算中的三个“高大上”的你一定听说过云计算中的三个“高大上”的概念:IaaS.PaaS和SaaS,这几个术语并不好理解.不过,如果你是个吃货,还喜欢披萨,这个问题就好解决了!好吧,其实你 ...
- 为何你跟着滴滴D8级前端大神撸代码,技术却依旧原地踏步?
引子 听说最近有很多小伙伴,热衷于在慕课网上学习各种前端实战教程,并以完成项目为奋斗目标.比如本文接下来要提到的<Vue2.0高级实战之开发移动端音乐App>,这门课程的传授者是来自滴滴D ...
- 对话机器学习大神Yoshua Bengio(上)
Yoshua Bengio教授(个人主页)是机器学习大神之一,尤其是在深度学习这个领域.他连同Geoff Hinton老先生以及 Yann LeCun(燕乐存)教授,缔造了2006年开始的深度学习复兴 ...
- 对话机器学习大神Yoshua Bengio(下)
对话机器学习大神Yoshua Bengio(下) Yoshua Bengio教授(个人主页)是机器学习大神之一,尤其是在深度学习这个领域.他连同Geoff Hinton老先生以及 Yann LeCun ...
- zz独家专访AI大神贾扬清:我为什么选择加入阿里巴巴?
独家专访AI大神贾扬清:我为什么选择加入阿里巴巴? Natalie.Cai 拥有的都是侥幸,失去的都是人生 关注她 5 人赞同了该文章 本文由 「AI前线」原创,原文链接:独家专访AI大神贾扬清:我 ...
- 【web前端面试题整理04】阿里一行之大神面对面
前言 这段时间我在河南一家公司当了一段时间的前端主管,最后可耻的匿了,原因各种各样,最主要的就是不想呆在郑州了. 其实这里的同事还是很不错的,面对老总最后的挽留我不是没有动心,而是这个地方确实不太好, ...
- ScrollView嵌套ListView的滑动冲突问题,是看大神的方法的,作为学习以后用的到
在工作中,曾多次碰到ScrollView嵌套ListView的问题,网上的解决方法有很多种,但是杂而不全.我试过很多种方法,它们各有利弊. 在这里我将会从使用ScrollView嵌套ListView结 ...
- Github欢乐多 PHP神级代码引发吐槽热
前日,github的PHP板块惊现一段能够提升70%运行效率的代码,引发了全世界众多网友的吐槽和调侃,“awesome!”.“well done!”.“PHP是世界第一语言!”平时不苟言笑,埋头苦干的 ...
随机推荐
- Vue-搭建环境
项目开发完react-native,因为又对vue开始感兴趣了,又开始自学起了vue,关于vue是一个很简便的前端框架,要学习它,当然是要先学会搭建vue的环境, 不会搭建环境的程序员不是一个好的程序 ...
- proxy配置
关于config.js里面proxy的配置: proxy: { '/api': { target: 'http://192.168.***.**:8500', cha ...
- LeetCode--022--括号生成(python)
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n = 3,生成结果为: class Solution: def generateParenth ...
- python+selenium实现经京东登录+购物+支付
import json from time import sleep from selenium import webdriver import chardet from selenium.webdr ...
- React Native 之项目的启动
运行项目有两种方法 1. 到根目录,执行 react-native run-ios 命令 会开启一个本地服务,加载jsbundle文件,然后是去index.js文件 import {AppRegist ...
- spring boot mapper层传参数是用main的arg0(第一个参数),arg1(第二个参数)
spring boot mapper层传参数是用main的arg0(第一个参数),arg1(第二个参数) 大于三个参数,用map传递 public interface FrontMapper{ //= ...
- 跳转控制语句continue
1 continue的使用场景: 1.1 在循环语句中 注意:离开使用场景的存在是没有意义的 2 continue的作用: 2.1 单层循环对比break,然后总结两者的区别 2.1.1 break ...
- ASP.net 能写一个上传整个文件夹的东东
IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag 客户端每次提交下载请求时,服务 ...
- MongoDB可视化工具的安装
MongoDBCompass MongoDB Compass是一款优秀可靠的mongodb可视化数据库管理软件.可以更加方便地与mongodb数据库进行交互,支持对数据库进行查询.分析或者查看数据库的 ...
- CopyOnWrite 个人理解以及应用
缘由 最近在看<Redis 设计与实现>,看到Redis的执行bgsave生成dump.rdb是根据CopyOnWrite的 之前也不是很懂为啥要有CopyOnWrite这个东西 翻看文章 ...