Sql 如何消除子查询在";中的重复;。。其中X在(S)或Y在(S)中;?
我有一个查询,需要从另一个查询中存在两个外键的表中获取行。以下是简化的SQL:Sql 如何消除子查询在";中的重复;。。其中X在(S)或Y在(S)中;?,sql,sql-server,subquery,Sql,Sql Server,Subquery,我有一个查询,需要从另一个查询中存在两个外键的表中获取行。以下是简化的SQL: Select MainID From MainTable Where Key1 In (Select SubID From SubTable Where UserID=@UserID) Or Key2 In (Select SubID From SubTable Where UserID=@UserID) 如您所见,子查询是重复的。SQL编译器是否足够智能,可以识别这一点并只运行一次子查询,还是运行两次 有没有更好
Select MainID From MainTable Where
Key1 In (Select SubID From SubTable Where UserID=@UserID) Or
Key2 In (Select SubID From SubTable Where UserID=@UserID)
如您所见,子查询是重复的。SQL编译器是否足够智能,可以识别这一点并只运行一次子查询,还是运行两次
有没有更好的方法来编写这个SQL
更新:我本来应该提到这一点-SubID是SubTable上的主键。我认为编译器不够智能,无法执行一次表扫描或索引查找 如果您有一个复杂的
where子句
,则可以将子查询
结果推入临时表
。
现在使用where
子句中的temp表,它将具有更好的性能
SELECT SubID
INTO #SubTable
FROM SubTable
WHERE UserID = @UserID
SELECT MainID
FROM MainTable M
WHERE EXISTS (SELECT 1
FROM #SubTable
WHERE M.Key1 = S.SubID)
OR EXISTS (SELECT 1
FROM #SubTable
WHERE M.Key2 = S.SubID)
我认为编译器不够智能,不能一次完成表扫描或索引查找 如果您有一个复杂的
where子句
,则可以将子查询
结果推入临时表
。
现在使用where
子句中的temp表,它将具有更好的性能
SELECT SubID
INTO #SubTable
FROM SubTable
WHERE UserID = @UserID
SELECT MainID
FROM MainTable M
WHERE EXISTS (SELECT 1
FROM #SubTable
WHERE M.Key1 = S.SubID)
OR EXISTS (SELECT 1
FROM #SubTable
WHERE M.Key2 = S.SubID)
可以使用公共表表达式:
with subid_data as (
Select SubID
From SubTable
Where UserID=@UserID
)
Select MainID
From MainTable
Where Key1 In (select SubID from subid_data)
Or Key2 In (select SubID from subid_data);
可以使用公共表表达式:
with subid_data as (
Select SubID
From SubTable
Where UserID=@UserID
)
Select MainID
From MainTable
Where Key1 In (select SubID from subid_data)
Or Key2 In (select SubID from subid_data);
您将用EXISTS子句替换IN子句:
Select MainID From MainTable
Where Exists
(
Select *
From SubTable
Where UserID = @UserID
And SubID in (MainTable.Key1, MainTable.Key2)
);
您将用EXISTS子句替换IN子句:
Select MainID From MainTable
Where Exists
(
Select *
From SubTable
Where UserID = @UserID
And SubID in (MainTable.Key1, MainTable.Key2)
);
请尝试以下查询:
Select MainID
From MainTable m
Where exists
( select 1 from SubTable s Where s.UserID=@UserID and s.sub_id in (m.key1,m.Key2))
请尝试以下查询:
Select MainID
From MainTable m
Where exists
( select 1 from SubTable s Where s.UserID=@UserID and s.sub_id in (m.key1,m.Key2))
tldr;原始的和下面的联接建议(具有较少的“看起来冗余”)都应该生成等效的查询计划。如果对SQL Server[当前]如何处理查询有任何疑问。(请参阅以了解魔法的味道。)
SQL编译器是否足够智能,可以识别这一点并只运行一次子查询,还是运行两次
是的,SQL Server足够聪明来处理这个问题。它不需要“运行两次”(nit:子查询在过程意义上根本不“运行”)。也就是说,没有强制的显式物化阶段——更不用说两个了。下面的连接转换说明了为什么不需要这样的连接
由于这些是独立(或不相关)的子查询1,因为它们不依赖于外部查询,因此它们可以——我敢说将——进行优化,因为它们可以在规则下自由、轻松地移动
如您所见,子查询是重复的。。有没有更好的方法来编写这个SQL
然而,它在视觉上仍然“看起来多余”,因为它是这样写的。SQL Server不在乎,但人类可能会在乎。因此,下面是我如何写它以及我认为“更好”的内容。
我非常喜欢在子查询上使用连接;一旦采用连接方法,它通常“更适合”RA。由于原始子查询的不相关性质,[SQL Server]查询计划器能够在内部执行这样的RA重写,因此可以将此简单转换为联接;查看实际的查询计划,以查看存在哪些差异(如果有)
然后,重写查询将是:
Select MainID
From MainTable
Join (
Select Distinct SubID -- SubId must be unique from select
From SubTable
Where UserID=@UserID
) t
-- Joining on "A or B" may indicate an ARC relationship
-- but this obtains the original results
On Key1 = t.SubID
Or Key2 = t.SubID
DISTINCT被添加到,因为SubId列的多重性未知(对我来说),如果SubId被唯一约束绑定,则SQL Server可以将其视为冗余限定符,因此它是必需的或“自由的”。有关连接的表键是唯一的原因,请参见
注意:如中所述,SQL Server不一定如上图所示将IN重写到联接中;但是仍然使用能够移动RA操作(并且能够将查询视为是什么而不是如何)的基本概念
1一些答案将原始子查询更改为独立/相关子查询,即。当SQL Server尝试“撤消”更改时,它仍然可能会产生一个值得尊敬的(甚至是等效的)查询计划——但这离干净的RA模型和连接还有一步之遥!(如果SQL Server无法“撤消”添加的相关性,那么查询将远不如SQL Server。);原始的和下面的联接建议(具有较少的“看起来冗余”)都应该生成等效的查询计划。如果对SQL Server[当前]如何处理查询有任何疑问。(请参阅以了解魔法的味道。) SQL编译器是否足够智能,可以识别这一点并只运行一次子查询,还是运行两次 是的,SQL Server足够聪明来处理这个问题。它不需要“运行两次”(nit:子查询在过程意义上根本不“运行”)。也就是说,没有强制的显式物化阶段——更不用说两个了。下面的连接转换说明了为什么不需要这样的连接 由于这些是独立(或不相关)的子查询1,因为它们不依赖于外部查询,因此它们可以——我敢说将——进行优化,因为它们可以在规则下自由、轻松地移动 如您所见,子查询是重复的。。有没有更好的方法来编写这个SQL 然而,它在视觉上仍然“看起来多余”,因为它是这样写的。SQL Server不在乎,但人类可能会在乎。因此,下面是我如何写它以及我认为“更好”的内容。 我非常喜欢在子查询上使用连接;一旦采用连接方法,它通常“更适合”RA。由于原始子查询的不相关性质,[SQL Server]查询计划器能够在内部执行这样的RA重写,因此可以将此简单转换为联接;查看实际的查询计划,以查看存在哪些差异(如果有) 然后,重写查询将是:
Select MainID
From MainTable
Join (
Select Distinct SubID -- SubId must be unique from select
From SubTable
Where UserID=@UserID
) t
-- Joining on "A or B" may indicate an ARC relationship
-- but this obtains the original results
On Key1 = t.SubID
Or Key2 = t.SubID
DISTINCT被添加到,因为SubId列的多重性未知(对我来说),如果SubId被唯一约束绑定,则SQL Server可以将其视为冗余限定符,因此它是必需的或“自由的”。有关连接的表键是唯一的原因,请参见
注意:如中所述,SQL Server不一定如上图所示将IN重写到联接中;但是芬达门