in 和exists

对于以上两种查询条件,in是把外表和内表作hash 连接,而exists 是对外表作loop 循环,每次loop 循环再对内表进行查询。

一直以来认为exists 比in 效率高的说法是不准确的。在不同的情况下,exists与in的性能各有优缺项,如果查询的两个表大小相当,那么用in 和exists 差别不大。

下面以实例来进行说明:

select *  from A where id in(select id from B);

select *  from A where exists (select 1 from B where A.id = B.id);

1、in的应用原理

在select *  from A where id in(select id from B); 中,in()中的子查询只执行一次,它查询出B表中的所有ID值并缓存起来;之后,在内存中检查A表的id是否与B表中的id值相等,如果相等则则将A表的记录加入到结果集中,直到遍历完A表中的所有记录。

它查询的过程类似于一下过程

Array A={select * from A};
Array B={select id from B};
for (int i=0;i<A.length;i++){
for (int j=0;j<B.length;j++){
if (A[i].id == B[j].id){
resultSet.add(A[i]);
break;
}
}
}

如:A表有10000条记录,B表有1000000条记录,那么使用in最多可能有10000*1000000次遍历,效率很差;

A表有10000条记录,B表有100条记录,那么使用in最多可能有10000*100次遍历,遍历次数大大减少,效率大大提升;

结论:in()适合B表比A表数据小的情况

2、exists的应用原理

在select * from A where exists (select 1 from B where A.id=B.id);之中
exists()会执行A.length次,它并不缓存exists()结果集,因为exists()结果集的内容并不重要,重要的是其内查询语句的结果集空或者非空,空则返回false,非空则返回true。
它的查询过程类似于以下过程:

Array A=(select * from A);
for(int i=0;i<A.length;i++) {
if(exists(A[i].id) { //执行select 1 from B where B.id=A.id是否有记录返回
resultSet.add(A[i]);
}
}
return resultSet;

当B表比A表数据大时适合使用exists(),因为它没有那么多遍历操作,只需要再执行一次查询就行。
如:A表有10000条记录,B表有1000000条记录,那么exists()会执行10000次去判断A表中的id是否与B表中的id相等。
如:A表有10000条记录,B表有100000000条记录,那么exists()还是执行10000次,因为它只执行A.length次,可见B表数据越多,越适合exists()发挥效果。
再如:A表有10000条记录,B表有100条记录,那么exists()还是执行10000次,还不如使用in()遍历10000*100次,因为in()是在内存里遍历比较,而exists()需要查询数据库,我们都知道查询数据库所消耗的性能更高,而内存比较很快

结论:exists()适合B表比A表数据大的情况

当A表数据与B表数据一样大时,in与exists效率差不多,可任选一个使用。

数据从一个表往另外一个表中插入数据时使用EXISTS:

在插入记录前,需要检查这条记录是否已经存在,只有当记录不存在时才执行插入操作,可以通过使用 EXISTS 条件句防止插入重复记录。
insert into A (name,age) select name,age from B where not exists (select 1 from A where A.id=B.id);

EXISTS与IN的使用效率的问题,通常情况下采用exists要比in效率高,因为IN不走索引。但要看实际情况具体使用:IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况。

关于EXISTS:
EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值TRUE 或FLASE 。
EXISTS指定一个子查询,检测行的存在。
语法:EXISTS subquery
参数:subquery 是一个受限的 SELECT 语句 (不允许有 COMPUTE 子句和 INTO 关键字)。
结果类型:Boolean 如果子查询包含行,则返回 TRUE ,否则返回 FLASE 。
结论:select * from A where exists (select 1 from B where A.id=B.id) 
EXISTS(包括 NOT EXISTS )子句的返回值是一个boolean值。 EXISTS内部有一个子查询语句(SELECT ... FROM...), 我将其称为EXIST的内查询语句。其内查询语句返回一个结果集。 EXISTS子句根据其内查询语句的结果集空或者非空,返回一个布尔值。
一种通俗的可以理解为:将外查询表的每一行,代入内查询作为检验,如果内查询返回的结果取非空值,则EXISTS子句返回TRUE,这一行行可作为外查询的结果行,否则不能作为结果。
分析器会先看语句的第一个词,当它发现第一个词是SELECT关键字的时候,它会跳到FROM关键字,然后通过FROM关键字找到表名并把表装入内存。接着是找WHERE关键字,如果找不到则返回到SELECT找字段解析,如果找到WHERE,则分析其中的条件,完成后再回到SELECT分析字段。最后形成一张我们要的虚表。
WHERE关键字后面的是条件表达式。条件表达式计算完成后,会有一个返回值,即非0或0,非0即为真(true),0即为假(false)。同理WHERE后面的条件也有一个返回值,真或假,来确定接下来执不执行SELECT。

Sql中EXISTS与IN的使用及效率的更多相关文章

  1. SQL中EXISTS怎么用[转]

    SQL中EXISTS怎么用 1 2 3 4 分步阅读 EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False 方法/步骤 1 EXISTS用于 ...

  2. SQL中EXISTS和IN用法

    SQL中EXISTS的用法  指定一个子查询,检测行的存在. 语法:EXISTS subquery 参数:subquery 是一个受限的 SELECT 语句 (不允许有 COMPUTE 子句和 INT ...

  3. sql中exists和not exists的用法

    该文转载自:http://www.cnblogs.com/mytechblog/articles/2105785.html sql中exists,not exists的用法 exists : 强调的是 ...

  4. 十、SQL中EXISTS的用法 十三、sql server not exists

    十.SQL中EXISTS的用法 EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False EXISTS 指定一个子查询,检测 行 的存在. 语法 ...

  5. sql 中 exists用法

    SQL中EXISTS的用法   比如在Northwind数据库中有一个查询为SELECT c.CustomerId,CompanyName FROM Customers cWHERE EXISTS(S ...

  6. 数据库——SQL中EXISTS怎么用2(转)

    数据库sql语句的exists总结 sql exists in 学习 先来比较下语法: --deals=交易表,areas=地域表,例如香港:我们的目的:查看有交易的地域 select * from ...

  7. sql中exists和notexists用法总结(并和in的比较)

    首先头脑中有三点概念: 1.EXISTS子查询找到的提交 NOT EXISTS 子查询中 找不到的提交 说明:不要去翻译为存在和不存在,把脑袋搞晕. 2.建立程序循环的概念,这是一个动态的查询过程.如 ...

  8. SQL中EXISTS的使用

    1.简介 不相关子查询:子查询的查询条件不依赖于父查询的称为不相关子查询. 相关子查询:子查询的查询条件依赖于外层父查询的某个属性值的称为相关子查询,带EXISTS 的子查询就是相关子查询 EXIST ...

  9. SQL中exists、not exists以及in、not in的区别和使用

    exists : 强调的是是否返回结果集,不要求知道返回什么, 比如:   select name from student where sex = 'm' and mark exists(selec ...

随机推荐

  1. centos7 图形化界面

    当你安装centos服务器版本的时候,系统默认是不会安装 CentOS 的图形界面程序的,比如:gnome或者kde, 那么如果你想在图形界面下工作的话,可以手动来安装CentOS Gnome GUI ...

  2. redis集群尝试

    1. 使用Docker搭建redis主从复制集群 安装参照 Docker 搭建redis 集群 启动服务 docker run --name redis-master -p 6379:6379 -d ...

  3. code signing is required for product type 'Application' in SDK 'iOS 8.1' 错误分析以及解决方案

    在真机测试的时候往往会突然出现这样一个错误,code signing is required for product type 'Application' in SDK 'iOS 7.0'  ,就是说 ...

  4. python读取grib grib2气象数据

    如何读取GRIB数据?快看Python大神整理的干货! 橙子心法 百家号17-11-0116:30 GRIB是WMO开发的一种用于交换和存储规则分布数据的二进制文件格式,主要用来表示数值天气预报的产品 ...

  5. Weblogic重起后打开控制台登陆后响应极慢

    linux下Weblogic 重启后第一次打开console登陆后响应极慢(20多分钟)(锁定并编辑第一次也极慢),以后速度就正常了,重启后又会极慢! 在网上看了看,是说linux下的java生成随机 ...

  6. web.xml配置重理解

    <context-param> <param-name>home-page</param-name> <param-value>home.jsp< ...

  7. python中的get

    get()根据键获取字典中的值,如果键不存在则返回一个默认值,默认值不填写则返回None 1 a = { 2 "name":"dlrb", 3 "ag ...

  8. iOS基础知识之类别

    本类从三个方面介绍iOS中的类别,分别是  什么是类别:类别的语法:类别的作用.具体内容如下: 一.类别: 类的补丁:当不能获取现有类的源码,但需要对现有类的功能进行补充时,这种情况下使用类别. 类别 ...

  9. php CURL模拟GET、POST请求。

    /** * get * @param string $url 请求地址 */ function GetHttp($url){ // 关闭句柄 $curl = curl_init(); // 启动一个C ...

  10. django之block extend标签

    class ExtendsNode(Node): must_be_first = True context_key = 'extends_context' def __init__(self, nod ...