T-SQL:可选的表连接?

Joh*_*ohn 6 t-sql sql-server-2008

假设我有一个存储过程,它会在参数时执行复杂的逻辑@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))
Run Code Online (Sandbox Code Playgroud)

这很好用; 但是,我认为将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
Run Code Online (Sandbox Code Playgroud)

Phi*_*ley 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
Run Code Online (Sandbox Code Playgroud)

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

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


use*_*019 5

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

因此,我会更喜欢编写程序

if @ComplicatedSearch = 1
   exec simple_search
else
   exec complex_search
Run Code Online (Sandbox Code Playgroud)

其中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
Run Code Online (Sandbox Code Playgroud)

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