EXISTS 与 IN 的 比较

简介:

Exists:

根据子查询是否返回行,该谓词返回true或false,不同于其他谓词和逻辑表达式,无论输入子查询是否返回行,Exists都不会返回unknown。如果子查询的筛选器为某一行返回unknown,则该行不返回。在筛选器中,unknown被认为类似于false,换句话说,当输入子查询包含一个筛选器时,只要该筛选器至少为一行得到true,则Exists将返回true。

在Exists谓词的子查询中,Exists只关心行是否存在,不关心特定属性,优化器将忽略子查询中的select列表。

在SQL SERVER 2000之前的版本,两者其实是有区别的,优化器会为他们生成不同的执行计划,而且EXISTS的性能更好,因为它具有短路功能.在SQL SERVER 2000及之后的版本,优化器通常会为两逻辑等价的查询生成相同的计划.


大家意识到EXISTS和IN有区别,争议之处都集中在SQL的三值逻辑(true,false,unknown)上,不同于EXISTS,当输入列表包含NULL时,IN实际上回产生一个UNKNOWN逻辑结果.例如: IN(b,c,NULL)的结果是UNKNOWN.然而,因为在筛选器中UNKNOWN与FALSE的处理方式类似,使用IN和EXISTS查询的结果是一样的,所以优化器会产生相同的执行计划.

接下来来比较一下NOT EXISTS和NOT IN是否也一样呢?先看NOT EXISTS的情况:

1.SELECT Customer,Customer_Description
2.FROM dbo.Customers As C
3.WHERE Country='CHINA'
4.AND NOT EXISTS
5.(
6. SELECT * FROM Orders As O
7. WHERE O.Customer=C.Customer
8.)

假设Orders表中包含一个Customer为NULL的订单,但它与我们无关,查询依然会得到所有来自CHINA,暂时没有订单的消费者.
该计划扫描Customers表并筛选来自CHINA的消费者.对于每个匹配的消费者,该计划对Orders.Customer 上的索引执行一次查找.在执行计划中会有一个TOP运算符,因为只需确定是否至少有一个订单与该消费者匹配.这就是EXISTS的短路功能.当Orders.Customer列的密度比较大(即包含大量重复),使用TOP特别高效.每个消费者只发生一次查找(Seek),只在叶级(索引的最底层)扫描一行,以查找一个而不是所有的匹配.

如果用NOT IN来解决相同的问题,SQL你可能会写成:

1.SELECT Customer,Customer_Description
2.FROM dbo.Customers As C
3.WHERE Country='CHINA'
4.AND Customer NOT IN(SELECT Customer FROM dbo.Orders)

尝试在Orders表中插入一条Customer为NULL的记录,你会发现,用NOT IN的语句返回空集,因为当Orders.Customer列包含NULL时,IN查询永远不会返回FALSE!!,而是返回TRUE和UNKNOWN,所以NOT IN只返回NOT TRUE或NOT UNKNOWN,不返回TRUE(这句是关键).
下面举例来解释,还是刚才的例子,假设Orders列表是(a,b,NULL), a IN (a,b,NULL)返回TRUE,那么a NOT IN (a,b,NULL)就返回 NOT TRUE,即FALSE,所以查询不返回a, 那么, c IN (a,b,NULL)时,逻辑结果是UNKNOWN,那么 c NOT IN (a,b,NULL)则返回 NOT UNKNOWN,还是UNKNOWN.所以c也不返回值,就是说,无论Customers表中的值是什么,只要Orders表中的Customer中有NULL值,该查询实际上不会返回任何结果.所以NOT EXISTS和NOT IN不是逻辑等价的.所以他们的执行计划是不一样的,返回的结果也会不一样.
在这种情况下,我们只要在NOT IN子查询中加一个筛选器排除NULL值就可以了,如上面SQL中,改为SELECT Customer FROM dbo.Orders WHERE Customer IS NOT NULL.
当然,在实际运用中,大家都不可能允许Orders表中的Customer列是NULL值的.但大家还是要注意,在使用NOT IN的时候,要保证子查询不存在NULL值!!

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Edwingu/archive/2008/11/12/3286146.aspx




原文发布时间为:2011-03-17


本文来自云栖社区合作伙伴CSDN博客,了解相关信息可以关注CSDN博客。

目录
相关文章
|
SQL 人工智能 关系型数据库
mysql中in 和exists的区别
mysql中in 和exists的区别
|
12月前
|
负载均衡 监控 算法
负载均衡的方法有哪些?
负载均衡的方法有哪些?
732 59
|
3月前
|
人工智能 自然语言处理 安全
国内主流Agent工具功能全维度对比:从技术内核到场景落地,一篇读懂所有选择
2024年全球AI Agent市场规模达52.9亿美元,预计2030年将增长至471亿美元,亚太地区增速领先。国内Agent工具呈现“百花齐放”格局,涵盖政务、金融、电商等多场景。本文深入解析实在智能实在Agent等主流产品,在技术架构、任务规划、多模态交互、工具集成等方面进行全维度对比,结合市场反馈与行业趋势,为企业及个人用户提供科学选型指南,助力高效落地AI智能体应用。
2829 144
|
8月前
|
XML 人工智能 Java
注入Java Bean的方式
本文总结了 Spring Boot 中常见的 Bean 注入方式,包括字段注入(`@Autowired`)、构造器注入(推荐)、Setter 方法注入、`@Resource` 按名称注入、`@Bean` 定义复杂 Bean、`@Value` 注入配置值、XML 配置、`ApplicationContextAware` 手动获取 Bean 以及 JSR-330 的 `@Inject`。同时分析了 Setter 注入逐渐被淡化的原因,强调构造器注入的不可变性和安全性优势,并推荐结合 Lombok 简化代码。文章还提供了按需选择注解的建议和最佳实践,帮助开发者根据场景选择合适的依赖注入方式。
604 49
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
11月前
|
消息中间件 缓存 NoSQL
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
|
运维 监控 搜索推荐
【电商搜索】现代工业级电商搜索技术-Ha3搜索引擎平台简介
【电商搜索】现代工业级电商搜索技术-Ha3搜索引擎平台简介
|
SQL 关系型数据库 MySQL
在 MySQL 中使用 Exists
【8月更文挑战第11天】
2031 0
在 MySQL 中使用 Exists
|
存储 NoSQL 分布式数据库
大数据存储技术(4)—— NoSQL数据库
大数据存储技术(4)—— NoSQL数据库
|
存储 算法 安全
深入详解ThreadLocal
在我们日常的并发编程中,有一种神奇的机制在静悄悄地为我们解决着各种看似棘手的问题,它就是 ThreadLocal 。
21973 9
深入详解ThreadLocal