【问题标题】:NOT EXISTS vs NOT IN [duplicate]不存在与不存在[重复]
【发布时间】:2013-01-23 11:49:08
【问题描述】:

我正在优化一些 SQL 查询(这可以被认为是我最近发布的问题的第 2 部分)并将一些 NOT IN 替换为 NOT EXISTS 谓词

我是否认为这样做的主要好处是,使用 NOT EXISTS 您可以获得这样的好处,即在找到单个匹配项时语句将终止,但 NOT IN 与计数子查询将不得不做一个完整的表扫描?

如果选择的数据包含 NULL,NOT IN 似乎也需要额外的工作,这是正确的吗?

在我在 proc 中实现它们之前,我需要确保在这两种情况下第二个语句优于第一个语句(并且在功能上等效):

案例一:

        --exclude sessions that were tracked as part of a conversion during the last response_time minutes
        -- AND session_id NOT IN (SELECT DISTINCT tracked_session_id    
        --                              FROM data.conversions WITH (NOLOCK)
        --                              WHERE client_id = @client_id
        --                              AND utc_date_completed >= DATEADD(minute, (-2) * cy.response_time, @date)
        --                              AND utc_date_completed <= @date     
        --                              AND utc_date_clicked <= @date)

        AND NOT EXISTS (SELECT 1
                            FROM data.conversions WITH (NOLOCK)
                            WHERE client_id = @client_id
                            AND utc_date_completed >= DATEADD(minute, (-2) * cy.response_time, @date)
                            AND utc_date_completed <= @date
                            AND utc_date_clicked <= @date
                            AND data.conversions.tracked_session_id = d.session_id
        )

案例 2:

        -- NOT EXISTS vs full table scan with COUNT(dashboard_id)                                   
        -- AND (SELECT COUNT(dashboard_id)
        --          FROM data.dashboard_responses WITH(NOLOCK)
        --          WHERE session_id = d.session_id
        --          AND cycle_id = cy.id
        --          AND client_id = @client_id) = 0

        AND NOT EXISTS(SELECT 1
                            FROM data.dashboard_responses
                            WHERE session_id = d.session_id
                            AND cycle_id = cy.id
                            AND client_id = @client_id)

干杯

【问题讨论】:

  • 执行计划没有告诉你NOT IN是否执行表扫描吗?我会亲自查看计划中关于性能/IO 统计的内容。
  • 不幸的是,我不能(轻松)对数据源运行这些存储过程以获得查询计划
  • 从 Oracle 10g 开始 IN/NOT 显式转换为 EXISTS/NOT。 NOT IN 与 NOT EXISTS 一样有效。但如果您的子查询可能返回 NULLS,请不要使用 NOT IN。

标签: sql sql-server optimization plsql


【解决方案1】:

正如你所说的那样,两者是不同的东西。如果不为IN 的项目的子查询包含NULL 则不会返回任何结果,因为没有任何内容等于NULL 并且没有任何内容不等于NULL(甚至不是NULL)。

假设您使用两者来获得相同的结果,只要您在IN 语句中处理NULL 值,两者之间就没有区别。优化器足够聪明,知道在消除 NULL 值或使用不可为空的列后两者是相同的,因此请使用相同的 ANTI SEMI JOIN

考虑这两个表:

CREATE TABLE T (ID INT NOT NULL PRIMARY KEY);
CREATE TABLE T2 (ID INT NOT NULL PRIMARY KEY);

这两个查询得到完全相同的执行计划:

SELECT  *
FROM    T
WHERE   ID NOT IN (SELECT ID FROM T2);

SELECT  *
FROM    T
WHERE   NOT EXISTS (SELECT ID FROM T2 WHERE T.ID = T2.ID);

因为优化器知道 T2.ID 是不可为空的列。第三张桌子:

CREATE TABLE T3 (ID INT);

在 ID 列既不是索引也不是可为空的情况下,这两个查询呈现非常不同的执行计划:

SELECT  *
FROM    T
WHERE   ID NOT IN (SELECT ID FROM T3);

SELECT  *
FROM    T
WHERE   NOT EXISTS (SELECT ID FROM T3 WHERE T.ID = T3.ID);

and NOT EXISTS 会更有效率。然而,这两个再次产生(基本上)相同的执行计划:

SELECT  *
FROM    T
WHERE   ID NOT IN (SELECT ID FROM T3 WHERE T3.ID IS NOT NULL);

SELECT  *
FROM    T
WHERE   NOT EXISTS (SELECT ID FROM T3 WHERE T.ID = T3.ID);

所有这些查询和示例数据都在SQL Fiddle

编辑

真正回答你的问题:

案例 1NOT INNOT EXISTS 的性能相同,如果 tracked_session_iddata.conversions 中的不可为空的列,或者您在 In 语句中添加 WHERE tracked_Session_id IS NOT NULL。如果该列不可为空并且您不排除空值,则性能将不一样,并且假设没有空值NOT EXISTS 的性能会更好,如果没有空值,结果将不一样所以性能没有可比性。

案例 2 样本数据实际上让我感到惊讶,我认为这不会被优化为 ANTI SEMI JOIN,并且已经写了一个答案,但就在保存编辑之前我想我最好检查一下,然后惊讶地发现:

SELECT  *
FROM    T
WHERE   (   SELECT  COUNT(*) 
            FROM    T3
            WHERE   T.ID = T3.ID
        ) = 0;

优化与NOT EXISTS 完全相同。所以看起来优化器比我想象的更聪明,如果你希望计数不是 0,它只会生成不同的计划。

SQL Fiddle for Case 2

【讨论】:

  • 在 mssql 2005 中,他们添加了对 count(*) = 0count(*) &gt; 0 的优化,因为许多人将这种语法用于 IF 语句。尽管存在是更好的选择,因为它在技术上是正确的。 blogs.technet.com/b/wardpond/archive/2007/08/27/…
【解决方案2】:

你说得对,空值有很大的不同。 NOT IN 查询检查每个元素是否确实不匹配。与 null 的比较不会产生明确的结果。因此,如果您的子查询包含 null,则不会将任何内容视为“NOT IN”。

See this SQL Fiddle example.

这种行为不直观的副作用是NOT IN 实际上并不是IN 的反面。

NOT EXISTS 查询没有这个问题。

对于哪个性能更好的笼统陈述,我会犹豫不决,因为这通常取决于发生的优化类型。这就是为什么如果您关心性能,能够找出执行计划很重要。

【讨论】:

    猜你喜欢
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-26
    • 2011-12-01
    • 1970-01-01
    • 2015-04-19
    相关资源
    最近更新 更多