【问题标题】:Changing not in clause to inner join将 not in 子句更改为内部联接
【发布时间】:2014-09-02 22:32:30
【问题描述】:

如何将以下查询转换为内连接并避免使用 distinct 来优化性能。

select distinct(GroupId) 
from   BatchQuotaIndividualQuotas 
where  BatchQuotaCommonSettingsID = 58 
       and 
       GroupId not in 
       (
           select distinct(groupid) 
           from   BatchQuotaIndividualQuotas 
           where  BatchQuotaCommonSettingsID = 58 
                  and ObjectiveFunctionTotalResultID is null 
       )

GroupId 不是主键。有多个行对应于一个 GroupId。我想选择没有任何 ObjectiveFunctionTotalResultID 为空的 GroupId。 -

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    首先,distinct不是函数,而是select语句的修饰符。您选择不同的字段值组合,而不是不同的单个字段。如果您有更多字段,括号实际上会调用语法错误。所以不是

    select
      distinct(groupid)
    

    但是

    select distinct
      groupid   
    

    其次,你根本不需要内在的 distinct。 in 列表中可能存在重复项,dbms 可能已经为您优化了。通过在内部查询中添加自己的distinct,您正在积极阻止优化器完成其工作。

    第三,如果您想拥有不同的组 ID,您仍然需要在外部查询中使用 distinct。内部连接不会改变这一点。此外,由于您希望获得必须匹配的记录,因此内部联接将无法解决问题。左连接可以做到这一点,但如果我正确解释了您的查询,您可以将其写为:

    select distinct
      GroupId
    from 
      BatchQuotaIndividualQuotas 
    where 
      BatchQuotaCommonSettingsID = 58 and 
      ObjectiveFunctionTotalResultID is not null
    

    可以将其更改为group by,就像我在下面所做的那样,但效果是一样的。 Group by 只是创建组,并且还必须删除重复项。 Group by 主要用于聚合。我不确定内部工作原理,但 group by 从理论上讲是一个更难的过程,因为数据库需要为这些聚合创建实际的组,而不是仅仅过滤掉重复项。可能这也会被优化,所以最后,下面的查询将执行和表现与上面的相同。

    select
      GroupId
    from 
      BatchQuotaIndividualQuotas 
    where 
      BatchQuotaCommonSettingsID = 58 and 
      ObjectiveFunctionTotalResultID is not null
    group by
      GroupId
    

    【讨论】:

    • 您的答案不正确,原因与 Alex 的答案下发布的原因相同
    • 显示向问题添加此类信息(表结构、键)的重要性。 :) 我会看看我能做什么。
    • 看了一下,你可以用left join 解决它,我在我的 - 虽然是 - 回答查询之前已经简要提到过。但是@Dan 已经在他的回答中制定了这个解决方案,所以你可以选择他的。 :)
    • 除了我发布了 2 个更好的答案
    • 不是意见问题,而是性能和可读性问题。这不是哲学
    【解决方案2】:

    您可以使用LEFT JOIN 获得类似的结果,然后将连接结果设置为NULL

    select distinct GroupId
    from   BatchQuotaIndividualQuotas A
    left join BatchQuotaIndividualQuotas B ON B.ObjectiveFunctionTotalResultID IS NULL 
                                          AND B.GroupId = A.GroupId
                                          AND B.BatchQuotaCommonSettingsID = 58
    where  A.BatchQuotaCommonSettingsID = 58
       AND B.GroupId IS NULL
    

    您也可以使用GROUP BYHAVING 获得相同的结果,尽管我怀疑这种方法会更快。

    select GroupId
    from   BatchQuotaIndividualQuotas 
    where  BatchQuotaCommonSettingsID = 58
    group by GroupId
    having SUM(CASE WHEN ObjectiveFunctionTotalResultID IS NULL THEN 1 ELSE 0 END) = 0
    

    【讨论】:

      【解决方案3】:

      如果您从 where 子句中删除 distinct,您的查询将运行得更快。

      这里有两种更好的写法

      count(ObjectiveFunctionTotalResultID) 将计算非空值

      SELECT GroupId
      FROM   BatchQuotaIndividualQuotas 
      WHERE  BatchQuotaCommonSettingsID = 58 
      GROUP BY GroupId
      HAVING count(ObjectiveFunctionTotalResultID) = count(*)
      

      或:

      EXCEPT 将包括不同的

      SELECT GroupId
      FROM   BatchQuotaIndividualQuotas 
      WHERE  BatchQuotaCommonSettingsID = 58 
      EXCEPT
      SELECT GroupId
      FROM   BatchQuotaIndividualQuotas 
      WHERE  BatchQuotaCommonSettingsID = 58 
      AND ObjectiveFunctionTotalResultID is null
      

      【讨论】:

        【解决方案4】:

        你能试试这个吗?

        select GroupId
        from   BatchQuotaIndividualQuotas 
        where  BatchQuotaCommonSettingsID = 58 
        and ObjectiveFunctionTotalResultID  IS NOT NULL
        GROUP BY GroupId
        

        相同的查询(如果我是正确的)带有一些修改过的流程。它不是通过子查询过滤掉 ID,而是在原地进行。

        【讨论】:

        • 这不会正常工作,因为 GroupId 不是主键。有多个行对应于一个 GroupId。我想选择没有任何 ObjectiveFunctionTotalResultID 为空的 GroupId。
        猜你喜欢
        • 2019-07-04
        • 1970-01-01
        • 2011-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-02
        • 2016-10-02
        • 1970-01-01
        相关资源
        最近更新 更多