SQL Server如何处理以下查询?

时间:2015-01-26 13:46:23

标签: sql sql-server

我想在我的数据库上运行以下查询:

SELECT 
    u.UserId, u.FullName, u.Location, csr.SponsorId
FROM 
    [User] u
LEFT JOIN 
    (SELECT 
         csr.SponsorId 
     FROM 
         ClubSponsorRelation csr 
     WHERE 
         csr.ClubId = @clubId) AS csr ON u.UserId = csr.SponsorId
WHERE 
    u.UserType = 'Sponsor'
    AND csr.SponsorId IS NULL

这基本上是尝试运行排除左连接,所有不在ClubSponsorRelation表中的用户都将被退回。

我的问题是关于WHERE u.UserType = 'Sponsor'行。 SQL Server是否会在左连接之前或之后考虑这一点?

如果在左连接之后应用WHERE,我该如何重写此查询,它只会在具有UserType'赞助商'的用户上应用左连接?是左视图甚至是最永久的方式吗?随着时间的推移,用户和ClubSponsorRelation会变得非常大,查询可能会经常运行。

5 个答案:

答案 0 :(得分:2)

这取决于执行引擎。最简单的检查方法是让服务器为您生成执行计划 - 例如,在Management Studio中,选中Include actual execution plan。这将使您更好地了解查询实际上将如何运行,以及为什么。

请注意,推理非常复杂,并且在许多情况下可能看起来反直觉 - 例如,如果统计信息显示查询将触及大多数行,则可能会忽略索引等。如果您想要合理结果,您希望在真实(实际缩放)的数据和正确维护的数据库上运行此操作。

对于一些代码审查 - 没有必要加入"子查询"。相反,只需使用具有两个条件的连接:

left join ClubSponsorRelation csr on csr.ClubId = @clubId and u.UserId = csr.SponsorId

每个新的MS SQL版本使用子查询的原因较少。但是,当然,分析是国王 - 在复杂的情况下,有太多的变量无法进行可靠的猜测。

要理解的另一个重要事项是,我们只讨论可能的性能问题 - 声明不能依赖于评估的顺序等。整个集/关系代数SQL的一部分是构建的上。

答案 1 :(得分:1)

试一试。使用Not Exists查找用户,因为您要查找ClubSponsorRelation选择csr.SponsorId中不存在的用户对我没有任何意义。

SELECT u.UserId,
       u.FullName,
       u.Location
FROM   [User] U
WHERE  NOT EXISTS (SELECT 1
                   FROM   ClubSponsorRelation csr
                   WHERE  u.UserId = csr.SponsorId
                   AND    csr.ClubId = @clubId)
       AND u.UserType = 'Sponsor' 

答案 2 :(得分:0)

通常,DBMS会对所有查询进行自己的查询优化,使用它(DBMS)认为最快的算法。所以它过滤,然后加入。 但最好的方法是查看Execution Plan

答案 3 :(得分:0)

这里的其他答案都集中在查询计划上,我不认为这就是你所追求的。 WHERE子句将应用于FROM子句创建的所有行,或者应用于单词中的JOIN之后。如果要在JOIN中应用过滤器,可以将其添加为另一个条件;

SELECT 
    u.UserId, 
    u.FullName, 
    u.Location, 
    csr.SponsorId
FROM 
    [User] u
        LEFT JOIN ClubSponsorRelation csr ON csr.SponsorId = u.UserId
                                         and csr.ClubId = @clubId
                                         and u.UserType = 'Sponsor'
WHERE 
    csr.SponsorId IS NULL

答案 4 :(得分:0)

由DBMS决定如何执行查询。由于订单不会影响结果,因此您不必过于担心。通常,优化器会找到最有效的方法。这可以是一种方式或另一种方式。最好只是相信它做得很好,只有在出现性能问题时才开始找到解决方法。

您的查询已经显示出防御性思维。您希望得到的用户不是指定俱乐部的赞助商。那么为什么不使用NOT IN或NOT EXISTS?这将是直截了当的方式(也更容易阅读)。优化器可能会决定在内部使用外连接,但为什么在使用普通查询遇到任何问题之前,您是否还想到这些技巧呢?

话虽如此,我建议使用NOT IN或NOT EXIST,只要它们表现良好。

select userid, fullname, location
from [User]
where usertype = 'Sponsor'
and userid not in 
(
  select sponsorid 
  from clubsponsorrelation
  where clubid = @clubid
);

或者:

select userid, fullname, location
from [User] u
where usertype = 'Sponsor'
and not exists
(
  select * 
  from clubsponsorrelation csr 
  where csr.clubid = @clubid 
  and csr.sponsorid = u.userid
);