SQL中的EXISTS和IN之间的区别?


443

SQL中的EXISTSand IN子句有什么区别?

我们EXISTS什么时候应该使用,什么时候应该使用IN

Answers:


224

exists关键字可以以这种方式被使用,但实际上它的预期的一种方式,以避免计数:

--this statement needs to check the entire table
select count(*) from [table] where ...

--this statement is true as soon as one match is found
exists ( select * from [table] where ... )

这在您if有条件语句的情况下最有用,例如exists它比起来要快得多count

in是最好的使用,你有一个静态列表通过:

 select * from [table]
 where [field] in (1, 2, 3)

in语句中有表时,使用会更有意义join,但是大多数情况下都没有关系。查询优化程序应以两种方式返回相同的计划。在某些实现中(大多数是较旧的版本,例如Microsoft SQL Server 2000),in查询将始终获得嵌套的连接计划,而join查询将酌情使用嵌套,合并哈希。更现代的实现更智能,即使在in使用时也可以调整计划。


2
您能否详细说明“当in语句中有表时,使用联接会更有意义,但这并不重要。查询优化程序会以两种方式返回相同的计划。”?不是查询优化器部分,而是您可以在其中JOIN代替的部分IN
farthVader

select * from [table] where [field] in (select [field] from [table2])返回与相同的结果(和查询计划)select * from [table] join [table2] on [table2].[field] = [table].[field]

@Sander却没有:第一个查询从返回所有列table,第二个查询从table和返回所有列table2。在某些(大多数是较旧的)SQL数据库中,in查询将实现为嵌套连接,而join查询可以嵌套,合并,散列等(最快的方式)。
基思

2
好的,我应该在select子句中指定列,但是您应该更新答案,因为它明确指出查询“将以任何一种方式返回相同的计划”。

exists可以在case语句中使用,因此它们也可以方便地使用,即select case when exists (select 1 from emp where salary > 1000) then 1 else 0 end as sal_over_1000
smooth_smoothie

125

EXISTS会告诉您查询是否返回任何结果。例如:

SELECT * 
FROM Orders o 
WHERE EXISTS (
    SELECT * 
    FROM Products p 
    WHERE p.ProductNumber = o.ProductNumber)

IN 用于将一个值与多个值进行比较,并且可以使用文字值,如下所示:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (1, 10, 100)

您还可以在IN子句中使用查询结果,如下所示:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (
    SELECT ProductNumber 
    FROM Products 
    WHERE ProductInventoryQuantity > 0)

3
上一个查询很危险,因为如果子查询不返回任何结果,它可能会失败。“ in”子句至少需要1个参数...
user2054927 '16

40
@ user2054927如果子查询不返回任何行,则最后一个查询将正确地不返回任何行-这样做没有危险!
Tony Andrews

最好的答案。
Aminadav Glickshtein

81

根据规则优化

  • EXISTSIN当子查询结果非常大时,速度比快得多。
  • INEXISTS当子查询结果非常小时,速度比快。

基于成本优化器

  • 没有区别。

21
你的论据证明?我认为IN不会比EXISTS快!
纳瓦兹2014年

22
@Nawaz为何IN总是比EXISTS慢呢?
2014年

2
实施不正确的查询优化器?我似乎在某些RDBM中发生了这种事情(尽管不完全是这种情况)...
Haroldo_OK 2015年

1
EXISTS返回纯布尔值,这总是比必须比较大于BIT /布尔类型的字符串或值快。IN可以是布尔比较,也可以不是。由于编程更喜欢使用EXPLICIT来提高稳定性(ACID的一部分),因此EXISTS通常是首选。
clifton_h

2
为什么要这么多次投票?完全没有理由为什么这个基于假设的陈述通常是正确的。
卢卡斯·埃德

40

我假设您知道它们的作用,因此使用方式有所不同,所以我将理解您的问题:什么时候重写SQL以使用IN代替EXISTS是个好主意,反之亦然。

这是一个公平的假设吗?


编辑:我要问的原因是,在许多情况下,您可以基于IN重写SQL以改用EXISTS,反之亦然,对于某些数据库引擎,查询优化器将对二者进行不同处理。

例如:

SELECT *
FROM Customers
WHERE EXISTS (
    SELECT *
    FROM Orders
    WHERE Orders.CustomerID = Customers.ID
)

可以重写为:

SELECT *
FROM Customers
WHERE ID IN (
    SELECT CustomerID
    FROM Orders
)

或加入:

SELECT Customers.*
FROM Customers
    INNER JOIN Orders ON Customers.ID = Orders.CustomerID

所以我的问题仍然存在,原始的发布者是否想知道IN和EXISTS的功能,以及如何使用它,还是他问是否还要使用IN重写SQL以使用EXISTS来代替,反之亦然,这将是一个好主意吗?


12
我不知道OP,但是我想回答这个问题!什么时候应该对返回ID的子查询使用EXISTS而不是IN?
罗伊·廷克

8
在中JOIN,您将需要一个DISTINCT
Jaider 2014年

4
伟大的示范,但几乎没有解决这个问题
刘俊臣

28
  1. EXISTSIN子查询结果很大时要快得多。
    INEXISTS子查询结果非常小时要快。

    CREATE TABLE t1 (id INT, title VARCHAR(20), someIntCol INT)
    GO
    CREATE TABLE t2 (id INT, t1Id INT, someData VARCHAR(20))
    GO
    
    INSERT INTO t1
    SELECT 1, 'title 1', 5 UNION ALL
    SELECT 2, 'title 2', 5 UNION ALL
    SELECT 3, 'title 3', 5 UNION ALL
    SELECT 4, 'title 4', 5 UNION ALL
    SELECT null, 'title 5', 5 UNION ALL
    SELECT null, 'title 6', 5
    
    INSERT INTO t2
    SELECT 1, 1, 'data 1' UNION ALL
    SELECT 2, 1, 'data 2' UNION ALL
    SELECT 3, 2, 'data 3' UNION ALL
    SELECT 4, 3, 'data 4' UNION ALL
    SELECT 5, 3, 'data 5' UNION ALL
    SELECT 6, 3, 'data 6' UNION ALL
    SELECT 7, 4, 'data 7' UNION ALL
    SELECT 8, null, 'data 8' UNION ALL
    SELECT 9, 6, 'data 9' UNION ALL
    SELECT 10, 6, 'data 10' UNION ALL
    SELECT 11, 8, 'data 11'
  2. 查询1

    SELECT
    FROM    t1 
    WHERE   not  EXISTS (SELECT * FROM t2 WHERE t1.id = t2.t1id)

    查询2

    SELECT t1.* 
    FROM   t1 
    WHERE  t1.id not in (SELECT  t2.t1id FROM t2 )

    如果t1您的id中具有空值,则查询1将找到它们,但查询2无法找到空参数。

    我的意思是IN不能将任何内容与null进行比较,因此它没有null的结果,但EXISTS可以将所有内容与null进行比较。


这个答案是汤姆凯特的感情(合理的简介asktom.oracle.com/pls/asktom/...
杰罗米法国

我认为这个答案是基于直觉的,这很公平。但这不是普遍适用的。例如,Ingres几乎肯定不是这样,它会将两个等效的SQL查询都解析为相同的QUEL查询,而当涉及到以多种方式编写同一件事时,它缺少SQL的“丰富性”。
2016年

仅当t2.id定义为“ NOT NULL”时,这两个查询在逻辑上等效。要授予表定义中不依赖项的等效性,第二个查询应为“ SELECT t1。* FROM t1 WHERE t1.id不在(SELECT t2.id FROM t2 ,其中t2.id不为null)”
DavidדודוMarkovitz

16

如果使用的是IN运算符,则SQL引擎将扫描从内部查询中获取的所有记录。另一方面,如果使用EXISTS,SQL引擎将在找到匹配项后立即停止扫描过程。


10

IN仅支持相等关系(或在NOT之前为相等)。
它是= any / = some的同义词,例如

select    * 
from      t1 
where     x in (select x from t2)
;

EXISTS支持各种关系类型,这些关系类型不能使用IN表示,例如-

select    * 
from      t1 
where     exists (select    null 
                  from      t2 
                  where     t2.x=t1.x 
                        and t2.y>t1.y 
                        and t2.z like '℅' || t1.z || '℅'
                  )
;

换个说法-

EXISTSIN之间据称的性能和技术差异可能是由特定供应商的实现/限制/错误引起的,但是很多时候,由于缺乏对数据库内部的了解,它们只是虚构的。

表的定义,统计信息的准确性,数据库配置和优化器的版本都会影响执行计划,从而影响性能指标。


支持您对性能的评论:在不关注特定DBMS的情况下,我们应该假定由优化器来确定最有效的方法。
Manngo

9

Exists关键字计算真或假,但IN关键字比较相应的子查询列的所有值。另一个Select 1可以与Exists命令一起使用。例:

SELECT * FROM Temp1 where exists(select 1 from Temp2 where conditions...)

但是IN效率较低,所以Exists速度更快。


5

我认为,

  • EXISTS需要将查询结果与另一个子查询匹配时。需要在SubQuery结果匹配的地方检索Query#1结果。加入的种类..例如,也选择已下订单表#2的客户表#1

  • IN用于检索特定列的值是否位于IN列表(1,2,3,4,5)中。例如,选择位于以下邮政编码中的客户,即zip_code值位于(....)列表中。

何时在另一个上使用......当您觉得它读起来合适时(更好地传达了意图)。


4

区别在于:

select * 
from abcTable
where exists (select null)

上面的查询将返回所有记录,而下面的查询将返回空。

select *
from abcTable
where abcTable_ID in (select null)

试试看,观察输出。


1
嗯...错误:[SQL0104]令牌)无效。在两种情况下。您是否正在使用特定的RDBMS?
jmarkmurphy

3

据我所知,当子查询返回一个NULL值时,整个语句变为NULL。在这种情况下,我们使用EXITS关键字。如果要比较子查询中的特定值,则使用IN关键字。


3

哪一个速度更快取决于内部查询获取的查询数量:

  • 当您的内部查询获取数千行时,EXIST将是更好的选择
  • 当您的内部查询获取几行时,IN会更快

EXIST评估是对还是错,但IN比较多个值。当您不知道记录是否存在时,应选择EXIST


3

原因是EXISTS运算符基于“至少找到”原理进行工作。它返回true,并且一旦找到至少一个匹配的行,就停止扫描表。

另一方面,当IN运算符与子查询结合使用时,MySQL必须首先处理该子查询,然后使用该子查询的结果来处理整个查询。

一般的经验法则是,如果子查询包含大量数据,则EXISTS运算符可提供更好的性能。

但是,如果子查询返回的结果集很小,则使用IN运算符的查询将执行得更快。




0

如果子查询返回多个值,则您可能需要执行外部查询-如果条件中指定的列中的值与子查询结果集中的任何值匹配。要执行此任务,您需要使用in关键字。

您可以使用子查询来检查是否存在一组记录。为此,您需要将exists子句与子查询一起使用。该exists关键字总是返回true或false值。


0

我相信这是一个简单的答案。您为什么不向在系统中开发该功能的人员检查呢?

如果您是MS SQL开发人员,这是直接来自Microsoft的答案。

IN

确定指定的值是否与子查询或列表中的任何值匹配。

EXISTS

指定一个子查询以测试是否存在行。



-1

EXISTS在性能上比IN快。如果大多数过滤条件都在子查询中,那么最好使用IN;如果大多数过滤条件都在主查询中,那么最好使用EXISTS。


该说法确实没有任何证据支持,是吗?
卢卡斯·埃德

-2

如果您使用IN运算符,则SQL引擎将扫描从内部查询中获取的所有记录。另一方面,如果我们使用EXISTS,则SQL引擎在找到匹配项后将立即停止扫描过程。


@ziggy解释吗?这几乎是公认的答案也所说的。在必须检查每条记录中,存在的记录只要发现一条就可以停止。
Ben Thurley 2014年

不,不正确。IN并且EXISTS可以等效并彼此转化。
卢卡斯·埃德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.