2009-08-17 5 views
2

Nous avons du code SQL que j'essaie d'optimiser. Dans le code est une vue qui est plutôt chère à exécuter. Pour le plaisir de cette question, appelons cela ExpensiveView. En haut de la vue, une requête se joint à la vue via deux sous-requêtes.Optimiser l'aide pour la requête sql

Par exemple:

select v1.varCharCol1, v1.intCol, v2.intCol from (
    select someId, varCharCol1, intCol from ExpensiveView where rank=1 
) as v1 inner join (
    select someId, intCol from ExpensiveView where rank=2 
) as v2 on v1.someId = v2.someId 

Un exemple jeu de résultats:

some random string, 5, 10 
other random string, 15, 15 

Cela fonctionne, mais il est lent depuis que je suis d'avoir à choisir entre ExpensiveView deux fois. Ce que je voudrais faire est d'utiliser une déclaration de cas pour sélectionner seulement une fois ExpensiveView.

Par exemple:

select someId, 
    case when rank = 1 then intCol else 0 end as rank1IntCol, 
    case when rank = 2 then intCol else 0 end as rank2IntCol 
from ExpensiveView where rank in (1,2) 

Je pourrais alors regrouper les résultats ci-dessus par someId et obtenir presque la même chose que la première requête:

select sum(rank1IntCol), sum(rank2Intcol) 
from (*the above query*) SubQueryData 
group by someId 

Le problème est le varCharCol1 que je besoin d'obtenir quand le rang est 1. Je ne peux pas l'utiliser dans le groupe puisque cette colonne contiendra des valeurs différentes quand le rang est 1 que quand le rang est 2.

Quelqu'un a-t-il des solutions pour optimiser la requête de sorte qu'il ne sélectionne qu'une seule fois depuis ExpensiveView et qu'il est toujours capable d'obtenir les données varchar?

Merci d'avance.

Répondre

3

Il est difficile de deviner puisque nous ne définition voyons pas votre vue, mais essayez ceci:

SELECT MIN(CASE rank WHEN 1 THEN v1.varCharCol1 ELSE NULL END), 
     SUM(CASE rank WHEN 1 THEN rank1IntCol ELSE 0 END), 
     SUM(CASE rank WHEN 2 THEN rank2IntCol ELSE 0 END) 
FROM query 
GROUP BY 
     someId 

Notez que dans la plupart des cas pour les requêtes comme celle-ci:

SELECT * 
FROM mytable1 m1 
JOIN mytable1 m2 
ON  … 

l'optimiseur SQL Server va juste construire un Eager Spool (un index temporaire), qui sera plus tard utilisé pour rechercher la condition JOIN, donc probablement ces astuces sont redondantes.

+0

Lors de l'utilisation d'un MIN contre un varchar où il y a NULLs, sont les NULLs ignorés? – bugfixr

+0

'@ Chu': oui. – Quassnoi

+0

Ok, j'ai implémenté ça et ça marche super! Mon ancienne requête, renvoyant 515 lignes a pris 6 secondes à exécuter. En utilisant le cas, il ne reste que quelques millisecondes. A propos de la mise en file d'attente d'Eagar ... Je ne sais pas pourquoi, mais il semble que SQL Server n'effectuait pas le spouleur d'Eager sur la requête d'origine. Cela a probablement à voir avec le fait que les requêtes sont vraiment des sous-requêtes ou que la clause where la gâchait. En tout cas, merci pour le conseil! – bugfixr

0
select someId, 
    case when rank = 1 then varCharCol1 else '_' as varCharCol1 
    case when rank = 1 then intCol else 0 end as rank1IntCol, 
    case when rank = 2 then intCol else 0 end as rank2IntCol 
from ExpensiveView where rank in (1,2) 

puis utiliser min() ou max dans la requête d'enceinte

Questions connexes