0

我的工作是维护一个大量使用 SQL server (MSSQL2005) 的应用程序。
到目前为止,中间服务器将 TSQL 代码存储在 XML 中,并在不使用存储过程的情况下发送动态 TSQL 查询。
因为我能够更改那些 XML 查询,所以我想将我的大部分查询迁移到存储过程。
问题如下:

我的大多数查询对一张表都有相同的 Where 条件

样本:

Select 
   .....
from ....
where ....
and (a.vrsta_id = @vrsta_id  or @vrsta_id = 0)
and (a.podvrsta_id = @podvrsta_id or @podvrsta_id = 0)
and (a.podgrupa_2 = @podgrupa2_id or @podgrupa2_id = 0)
and (
 (a.id in (select art_id from osobina_veze where podosobina_id in (select ado from dbo.fn_ado_param_int(@podosobina))
        group by art_id
        having count(art_id)= @podosobina_count ))
     or ('0' = @podosobina)
 )

它们在其他表上也具有相同的 where 条件。

我应该如何组织我的代码?
什么是正确的方法?
我应该创建将在所有查询中使用的表值函数,
还是在每次执行 proc 时使用 #Temp 表和简单的内部连接我的查询?或使用表值函数提交的#temp?
或者将所有查询都保留在这个大的 where 子句中,并希望索引能够完成它们的工作。
或使用 WITH(语句)

4

3 回答 3

2

我开始意识到在单个查询中进行如此复杂的搜索并不是一个好主意。

我更喜欢根据输入条件值构建 sql。这使得 rsql server 更容易为每次搜索构建更好的执行计划。这样,我敢打赌,您的查询有一个次优的执行计划。

我意识到这将包括动态 sql,因此适用于它的通常警告。

于 2010-06-16T14:31:16.680 回答
2

您在这里有两个不同的功能问题:从一个表中选择值以及选择要返回的列或要连接到该数据的其他表。如果您的一张桌子上过滤的项目数量可能很大,我倾向于将所选值的 PK 存储到中间或工作表中。如果它是一个永久表,您可以通过 SessionId 之类的东西来分隔不同的搜索,或者您可以通过从过滤例程传递到选择例程的随机值来分隔每组搜索结果。

没有理由不能在动态 SQL 中保留过滤例程。但是,我不会尝试在 T-SQL 中执行动态 SQL。T-SQL 对于字符串操作来说很糟糕。从中间层动态构建查询使您能够从 Where 子句中排除实际上未传递的元素。例如,and (a.vrsta_id = @vrsta_id or @vrsta_id = 0)您可以简单地完全排除这一行 when@vrsta_id实际上是零或 have a.vrsta_id = @vrsta_idwhen@vrsta_id不是零,而不是拥有 。通常,这种类型的查询将比一系列 OR 执行得更好。

有了工作表后,您的选择查询将类似于:

Select..
From WorkTable As W
    Join ...

Where SetId = 12345
    And ( OtherTable.Col = ....

在这种情况下,SetId将表示从过滤例程创建的项目集。

于 2010-06-16T15:05:59.340 回答
1

您可以创建一个接受参数并返回匹配 a.id 值的表的表值函数。然后,您可以将该函数内部连接到每个存储过程中的查询中。例如:

create function dbo.GetMatches
(
@vrsta_id int,
@podvrsta_id int,
@podgrupa2_id int,
@podosobina_count int
)
returns table
as
return
Select 
a.id
from a
where
(a.vrsta_id = @vrsta_id  or @vrsta_id = 0)
and (a.podvrsta_id = @podvrsta_id or @podvrsta_id = 0)
and (a.podgrupa_2 = @podgrupa2_id or @podgrupa2_id = 0)
and (
(a.id in (select art_id from osobina_veze where podosobina_id in (select ado from dbo.fn_ado_param_int(@podosobina))
group by art_id
having count(art_id)= @podosobina_count ))
or ('0' = @podosobina)
)

然后在此示例查询中...

select
*
from
a
inner join dbo.GetMatches(1,2,3,4) matches
on a.id = matches.id
inner join b on a.bID = b.bID -- example other table

您也可以像这样在 where 语句中使用该函数...

where
    a.id in (select id from dbo.GetMatches(1,2,3,4))
于 2010-06-16T15:25:06.207 回答