我想在我的数据库上运行以下查询:
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会变得非常大,查询可能会经常运行。
答案 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
);