2010-06-16 7 views
0

Mon travail est la maintenance d'une application qui utilise beaucoup le serveur SQL (MSSQL2005).
Jusqu'à présent, le serveur intermédiaire stocke les codes TSQL en XML et envoie des requêtes TSQL dynamiques sans utiliser les procs stockés.
Comme je suis capable de modifier ces requêtes XML, je souhaite migrer la plupart de mes requêtes vers des process stockés.
Question est que vous avez choisi:Optimisation du code TSQL

La plupart de mes requêtes ont même Lorsque les conditions contre une table

Exemple:

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) 
) 

Ils ont aussi même si les conditions sur autre table.

Comment organiser mon code?
Quelle est la bonne façon?
Dois-je faire une fonction de valeur de table que je vais utiliser dans toutes les requêtes
ou utiliser des tables #Temp et simples internes joindre ma requête à chaque fois que proc s'exécute? ou utilisez #temp classé par fonction de valeur table?
ou laisser toutes les requêtes avec cette grande clause where et espérer que l'index va faire leur travail.
ou utiliser WITH (instruction)

Répondre

2

Je me suis rendu compte que de telles recherches complexes dans une seule requête n'est pas vraiment une bonne idée.

Je préfère construire le déport SQL sur les valeurs de condition d'entrée. Cela permet au serveur rsql de construire un meilleur plan d'exécution pour chaque recherche. De cette façon, je parie que vous avez un plan d'exécution sous-optimal pour vos requêtes. Je me rends compte que cela inclut SQL dynamique, donc les avertissements habituels pour cela s'appliquent.

2

Vous avez ici deux préoccupations fonctionnelles différentes: la sélection des valeurs de votre table et le choix des colonnes à renvoyer ou d'autres tables à joindre à ces données. Si le nombre d'éléments du filtrage sur votre table peut être grand, je serais enclin à stocker le PK des valeurs sélectionnées dans une table de milieu ou de travail. S'il s'agit d'une table permanente, vous pouvez séparer différentes recherches par quelque chose comme SessionId ou vous pouvez simplement séparer chaque ensemble de résultats de recherche par une valeur aléatoire que vous passez de la routine de filtrage à la routine de sélection.

Il n'y a aucune raison que vous ne puissiez pas conserver la routine de filtrage en SQL dynamique. Cependant, je n'essaierais pas de faire du SQL dynamique dans T-SQL. T-SQL est horrible pour la manipulation de chaînes. La construction dynamique des requêtes à partir de votre niveau intermédiaire vous permet d'exclure des éléments de la clause Where qui ne sont effectivement pas transmis. Par exemple, au lieu d'avoir and (a.vrsta_id = @vrsta_id or @vrsta_id = 0), vous pouvez simplement exclure cette ligne tout à fait lorsque @vrsta_id est en fait zéro ou a.vrsta_id = @vrsta_id lorsque @vrsta_id n'est pas zéro. Généralement, ce type de requête fonctionnera mieux qu'une série d'OR.

Une fois que vous avez devrait ressembler à votre table de travail, vos requêtes de sélection:

Select.. 
From WorkTable As W 
    Join ... 

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

Dans ce cas, SetId représenterait l'ensemble des éléments qui ont été créés à partir de la routine de filtrage.

1

Vous pouvez créer une fonction de valeur table qui prend en compte les paramètres et renvoie une table de valeurs a.id correspondantes. Vous pouvez ensuite joindre cette fonction à la requête dans chacune de vos procédures stockées. Par exemple:

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) 
) 

Ensuite, dans cet exemple requête ...

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 

Vous pouvez également utiliser cette fonction dans la déclaration où comme ça ...

where 
    a.id in (select id from dbo.GetMatches(1,2,3,4))