Sql 如何消除子查询在";中的重复;。。其中X在(S)或Y在(S)中;?

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编译器是否足够智能,可以识别这一点并只运行一次子查询,还是运行两次 有没有更好

我有一个查询,需要从另一个查询中存在两个外键的表中获取行。以下是简化的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重写到联接中;但是芬达门