SQL Server如何处理以下查询?

SQL Server如何处理以下查询?,sql,sql-server,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

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

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
这基本上是试图运行一个排除左连接,所有不在ClubsonCorrelation表中的用户都将返回

我的问题是关于
的,其中u.UserType='赞助商'
行。SQL Server在左联接之前还是之后会考虑这一点


如果在左连接后应用
WHERE
,我如何重写此查询,使其仅对用户类型为“赞助商”的用户应用左连接?左视图是最永久的方式吗?随着时间的推移,用户和俱乐部的相关性将变得非常大,查询可能会经常运行。

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

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

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

left join ClubSponsorRelation csr on csr.ClubId = @clubId and u.UserId = csr.SponsorId
对于每个新的MS SQL版本,使用子查询的理由更少。但当然,分析是王道——在复杂的场景中,变量太多,无法进行可靠的猜测


需要了解的另一件重要事情是,我们这里只讨论可能的性能问题-语句不能依赖于求值顺序等。这是整个集合的一部分/关系代数SQL的基础。

通常,DBMS将对所有查询进行自己的查询优化,使用它所使用的算法(DBMS)思考是最快的。所以是过滤,然后加入。
但是最好的方法是查看执行计划,这里的其他答案都集中在查询计划上,我认为这不是你想要的。WHERE子句将应用于FROM子句创建的所有行,或者在单词中的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

试试这个。使用
Not Exists
查找用户,因为您想查找
clubsoncorrelation
中不存在的用户,选择
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' 

如何执行查询取决于DBMS。由于顺序不会影响结果,您不必太担心。通常,优化器会找到最有效的方法。这可以是一种方式,也可以是另一种方式。最好相信它能做好工作,只有在出现性能问题时才开始寻找解决办法

您的查询已经显示出防御思维。您希望获得的用户不是给定俱乐部的赞助商。那么为什么不使用notin或notexists呢?这将是一种直截了当的方法(也更容易阅读)。优化器可能会决定在内部使用外部联接,但为什么在正常查询出现任何问题之前还要费心考虑这些技巧呢

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

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


SQL通过可用的索引、统计数据和其他任何东西来决定其求值顺序——只要您的逻辑正确并且结果相同。不过,我会使用“exists()”条件,使查询更具可读性。我想Luaan已经回答了您的问题,但我可以说,您的左连接很奇怪,为什么不尝试一下:左连接ClubSponsorRelation csr.ClubId=@ClubId和u.UserId=csr.SponsorId。您还可以在其中添加“and u.UserType='shandor'”,并从where子句中删除。感谢所有的回复,我将仔细阅读它们,并在允许的情况下选择适当的答案。我真想知道为什么我的问题被否决了。这是一个合理的问题,我为我正在尝试的内容提供了输入,对我来说,我想知道的似乎很清楚……当然,这仍然是相同的操作——它只是给查询优化器一些提示。大概关键的一点是代数是不含糊的,它不依赖于运算的顺序。如果实际执行计划的结果不同,那只是因为优化器的限制(在执行计划中可以很好地看到),而不是因为基础查询,在本例中,基础查询是相同的。@Luaan-这是一个左连接,因此这不是相同的操作。例如,原始查询只返回发起人用户类型,我的查询返回所有用户类型。这是否正确取决于原始海报想要什么。你是对的,我没有抓住这一点。我没有注意到您也将
UserType
条件移动到了那里。我的评论是关于将前两个条件移动到单个联接中,而不是子查询上的联接。移动
UserType
会将其应用于与原来不同的集合。不幸的是,该查询不会返回预期结果。左连接必须在预筛选的用户表上运行,或者之后通过WHERE运行。
不在
将在
子查询
返回
NULL
时失败value@NoDisplayName当前位置但这在俱乐部中是一个多么奇怪的条目,当表格的唯一目的是显示俱乐部和赞助商之间的关系时?我完全同意您的看法,但仍然可能存在
Null
值。这只是一个建议。csr.SponsorID是检查我的左连接是否正确返回NULL,如果我遗漏了IS NULL。我之所以选择左连接,是因为我的一位同事说它的性能会比左连接好,因为这是一个查询,而不是子查询。我在想
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
);