假设我有一个存储过程,它会在参数@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
答案 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