2011-10-24 4 views
1

originale requête que je suis en train de réécrire:Réécriture requête SQL avec une sous-requête imbriquée

SELECT Table1.* 
FROM Table1 
INNER JOIN Table2 ON Table2.[IDENTITY]=Table1.ID 
WHERE Table2.Field1 = @value AND Table2.Field2 = '1' AND Table1.ID in 
(
    select Table1.ID from Table1 where Table1.Number in 
    (select Table1.Number from Table1 where [email protected]) 
) 

Note:. Dans la vraie requête, je liste toutes les colonnes au lieu d'utiliser * Tableau 1

Cette requête est légèrement déroutant, surtout depuis que j'ai changé les noms etc pour poster. En bref, il doit prendre un ID qui est passé et trouver tous les champs Table1.Number qui ont cet ID. Il existe une relation Plusieurs à 1 entre le numéro et l'ID. Donc, une fois que tous les nombres sont trouvés, je dois ensuite trouver la liste totale des ID qui utilisent l'un de ces nombres.

Quand je regarde les statistiques quand je lance la requête je reçois

Table 'Table1'. Scan count 3873, logical reads 135255, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'Table2'. Scan count 0, logical reads 7995, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

Je me sens le coupable est la sous-requête imbriquée. J'essaye d'écrire cela différemment depuis un moment, mais je n'arrive pas à le comprendre complètement. J'ai réécrit la deuxième requête imbriquée comme:

WHERE Table2.Field1 = @value AND Table2.Field2 = '1' AND Table1.ID in 
(
    select Table1.ID from Table1 
    INNER JOIN Table1 AS Table3 ON Table1.Number = Table3.Number 
    where [email protected] 
) 

Malheureusement, cela a abouti à des statistiques identiques. Je ne peux pas tout à fait comprendre comment supprimer la 2ème déclaration "in".

Est-ce la meilleure approche? Y en a t-il un meilleur? Ai-je raison de dire que ce genre de sous-requête est très mauvais en termes de performances et provoque donc des scans élevés et des lectures logiques que les statistiques IO me montrent?

EDIT: requête d'origine utilisée Table2. [IDENTITY] = Table1.MessageID. Cela devrait être Table2. [IDENTITY] = Table1.ID. J'ai mis à jour la requête ci-dessus pour refléter cela.

Répondre

2

Je crois que vous avez raison en ce que la sous-requête imbriquée provoque les statistiques que vous voyez. Lorsque vous avez une valeur qui traduit dans un ensemble comme celui-ci, je trouve souvent que la solution la plus performante consiste à placer les résultats de la sous-requête dans une table temporaire, puis à s'y joindre à la place. Cela empêche l'exécution en ligne de la sous-requête et devrait considérablement améliorer vos performances.

Le contenu de la sous-requête fait référence à une variable d'instruction statique mais ne fait référence à aucun élément de l'instruction externe. Cela signifie qu'il ne s'agit pas d'une sous-requête corrélée et que nous effectuons simplement la même opération encore et encore pour chaque ligne. Lorsque vous voyez une sous-requête comme celle-ci, c'est un choix d'optimisation facile pour déplacer l'opération en dehors de la sélection et référencer les données d'une manière plus appropriée.

Pour l'exemple fourni, vous vous feriez quelque chose comme

select distinct Table1.ID 
INTO #myTemp 
from Table1 where Table1.Number in 
(select Table1.Number from Table1 where [email protected]) 

Cela tournerait votre requête initiale en

SELECT Table1.* 
FROM Table1 
INNER JOIN Table2 ON Table2.[IDENTITY]=Table1.MessageID 
INNER JOIN #myTemp a on Table1.ID = a.ID 
WHERE Table2.Field1 = @value AND Table2.Field2 = '1' 

Je suppose que vous utilisez SQL2008 R2 de sorte que votre syntaxe peut différer en fonction de votre SGBDR.

+0

Merci pour votre aide. Trouvé une petite faute de frappe dans mon message original (MessageID était censé être ID). Votre changement m'a abaissé à 1 Scan et 1110 Logical Reads. – Equixor