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
);