T-SQL:可选的表连接?

时间:2011-11-08 15:54:14

标签: sql-server-2008 tsql

假设我有一个存储过程,它会在参数@ComplicatedSearch = 1时执行复杂的逻辑。当它设置为1时,我使用此过程可以返回的有效行填充变量表@ValidIds。当它为0时,逻辑被绕过,我们不需要过滤掉要返回的行。

所以,通过这个逻辑,我最终会得到一个这样的陈述:

SELECT
    m.*
    ,a.*
FROM
    MyTable m
    INNER JOIN AdditionalInfoTable a
       ON m.Id = a.MyTableId
WHERE
   (@ComplicatedSearch = 0 OR EXISTS(SELECT * FROM @ValidIds WHERE Id = m.Id))

这很好用;但是,我认为在适用时将MyTable加入@ValidIds更有效,而不是使用EXISTS(),尤其是当MyTable包含大量行时。

有没有办法在不编写多个查询的情况下执行下面的操作? (实际的查询非常大,因此有多个版本的连接和不连接都不是理想的)

SELECT
    m.*
    ,a.*
FROM
    MyTable m
    ONLY DO THIS IF ComplicatedSearch = 1 PLEASE: INNER JOIN @ValidIds v
       ON m.Id = v.Id
    INNER JOIN AdditionalInfoTable a
       ON m.Id = a.MyTableId

2 个答案:

答案 0 :(得分:6)

另一种选择:

SELECT
   m.*     
  ,a.*
FROM MyTable m    
 INNER JOIN @ValidIds v
  ON m.Id = case
              when @ComplicatedSearch = 1 then v.Id  --  Filter rows
              else m.Id  --  Select all rows
            end
 INNER JOIN AdditionalInfoTable a    
  ON m.Id = a.MyTableId

您需要进行性能测试,看看它是否足够高效。一些快速测试显示(根据我的数据)生成相同的查询计划,无论第一次调用是复杂还是非复杂。

“分叉”方法(单独的程序)应该是最有效的。但是,在两个不同的地方只需稍作修改即可获得相同的代码,这可能是一个很大的难点,特别是当您必须向该代码的所有“实例”添加后续更改时。如果数据的总体大小(例如整体性能)不是太大,那么“一种尺寸最适合所有”的方法可能是最有效的。

答案 1 :(得分:5)

如果您追求效率,则应注意存储过程将在第一次运行时计算查询计划,然后对其进行缓存并在此后使用相同的查询计划。在这种情况下,它意味着它将选择使用@ValidIds,具体取决于@ComplicatedSearch的第一个值

因此我会更像

编写程序
if @ComplicatedSearch = 1
   exec simple_search
else
   exec complex_search

其中simple_search包含您的第一个查询,complex_search也加入@ValidIds

你是否得到了两次查询,但为了克服这个问题,我会创建一个视图

create view helper as
begin
SELECT
    m.*
    ,a.*
FROM
    MyTable m
    INNER JOIN AdditionalInfoTable a
       ON m.Id = a.MyTableId
end

然后从该视图和复杂连接中简单选择@ValidIds