SQL中EXISTS和IN的区别?


Difference between EXISTS and IN in SQL?

SQL中的EXISTSIN子句有什么区别?

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


EXISTS关键字可以这样使用,但实际上它是为了避免计数:

1
2
3
4
5
--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条件语句的情况下最有用,因为EXISTScount快得多。

当您要传递静态列表时,最好使用IN

1
2
 SELECT * FROM [TABLE]
 WHERE [FIELD] IN (1, 2, 3)

当您在IN语句中有一个表时,使用join更为合理,但大多数情况下并不重要。查询优化程序应该以任何方式返回相同的计划。在某些实现中(大多数是较旧的,如Microsoft SQL Server 2000),IN查询将始终获得嵌套联接计划,而join查询将根据需要使用嵌套、合并或哈希。更现代的实现更智能,甚至在使用IN时也可以调整计划。


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

1
2
3
4
5
6
SELECT *
FROM Orders o
WHERE EXISTS (
    SELECT *
    FROM Products p
    WHERE p.ProductNumber = o.ProductNumber)

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

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

也可以将查询结果与IN子句一起使用,如下所示:

1
2
3
4
5
6
SELECT *
FROM Orders
WHERE ProductNumber IN (
    SELECT ProductNumber
    FROM Products
    WHERE ProductInventoryQuantity > 0)


基于规则优化器:

  • 当子查询结果很大时,EXISTSIN快得多。
  • 当子查询结果很小时,INEXISTS快。

基于成本优化器:

  • 没有区别。


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

这是一个公平的假设吗?

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

例如:

1
2
3
4
5
6
7
SELECT *
FROM Customers
WHERE EXISTS (
    SELECT *
    FROM Orders
    WHERE Orders.CustomerID = Customers.ID
)

可重写为:

1
2
3
4
5
6
SELECT *
FROM Customers
WHERE ID IN (
    SELECT CustomerID
    FROM Orders
)

或者加入:

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

所以我的问题仍然存在,最初的海报是不是想知道什么在里面,什么在里面,什么在里面存在,以及如何使用它,或者他是否要求重写一个使用in来使用exists的SQL,或者反过来,是一个好主意?


  • 当子查询结果很大时,EXISTSIN快得多。当子查询结果很小时,INEXISTS快。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    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'
  • 查询1

    1
    2
    3
    SELECT
    FROM    t1
    WHERE   NOT  EXISTS (SELECT * FROM t2 WHERE t1.id = t2.t1id)

    查询2

    1
    2
    3
    SELECT t1.*
    FROM   t1
    WHERE  t1.id NOT IN (SELECT  t2.t1id FROM t2 )

    如果在t1中,您的id值为空,那么查询1将找到它们,但查询2找不到空参数。

    我的意思是IN不能与空作比较,所以没有空的结果,但是EXISTS可以与空作比较。


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


    中只支持平等关系(或前面没有的不平等)。它是=any/=some的同义词,例如

    1
    2
    3
    4
    SELECT    *
    FROM      t1
    WHERE     x IN (SELECT x FROM t2)
    ;

    exists支持变量类型的关系,不能用in表示,例如-

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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 || '℅'
                      )
    ;

    。换个角度来说-

    据称存在和存在的性能和技术差异可能是由特定供应商的实现/限制/错误造成的,但很多时候它们只是由于对数据库内部的理解不足而产生的神话。

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


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

    1
    SELECT * FROM Temp1 WHERE EXISTS(SELECT 1 FROM Temp2 WHERE conditions...)

    但是IN效率较低,所以EXISTS更快。


    我想,

    • EXISTS是需要将查询结果与另一个子查询匹配的时候。如果子查询结果匹配,则需要检索查询1结果。有点像加入……例如,选择已下订单的客户表1表2

    • 在IS中,如果特定列的值位于IN列表(1、2、3、4、5),则检索该列表。例如,选择以下邮政编码的客户,即(…)列表中的邮政编码值。

    什么时候用一个比另一个…当你觉得它读得恰当时(更好地传达意图)。


    不同之处在于:

    1
    2
    3
    SELECT *
    FROM abcTable
    WHERE EXISTS (SELECT NULL)

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

    1
    2
    3
    SELECT *
    FROM abcTable
    WHERE abcTable_ID IN (SELECT NULL)

    试一下,观察输出。


    其原因是,现有的操作器是基于"至少找到"原则工作的。它返回true并在找到至少一个匹配行后停止扫描表。

    另一方面,当in操作符与子查询组合时,mysql必须首先处理子查询,然后使用子查询的结果处理整个查询。

    The general rule of thumb is that if the subquery contains a large
    volume of data, the EXISTS operator provides a better performance.

    However, the query that uses the IN operator will perform faster if
    the result set returned from the subquery is very small.


    哪个更快取决于内部查询获取的查询数:

    • 当您的内部查询获取数千行时,那么exist将是更好的选择。
    • 当您的内部查询提取几行时,那么in将更快。

    "存在"对"真"或"假"进行计算,但在"比较多个值"中进行计算。当您不知道记录是否存在时,应选择"存在"。


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


    我的理解是,只要我们不处理空值,两者都应该是相同的。

    查询不返回=空vs的值的原因相同,是空的。http://sqlinwild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

    至于boolean vs comparator参数,要生成一个boolean,两个值都需要比较,这就是任何if条件的工作方式,所以我无法理解in和existing的行为是如何不同的。.


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

    可以使用子查询检查是否存在一组记录。为此,需要在子查询中使用exists子句。exists关键字总是返回真或假值。


    江户十一〔七〕号

    https://docs.oracle.com/cd/b19306_01/server.102/b14211/sql_1016.htm_i28403


    我相信这是一个直截了当的答案。为什么你不从那些在他们的系统中开发这个功能的人那里检查它呢?

    如果您是MS SQL开发人员,下面是直接从Microsoft得到的答案。

    in号:

    Determines whether a specified value matches any value in a subquery or a list.

    exists号:

    Specifies a subquery to test for the existence of rows.


    我发现使用exists关键字通常非常慢(在Microsoft Access中是如此)。我使用join操作符的方式是:应该-i-use-the-keyword-exists-in-sql


    存在的性能比存在的快。如果大多数筛选条件都在子查询中,那么最好在中使用;如果大多数筛选条件都在主查询中,那么最好在存在时使用。


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