2011-01-21 5 views
2
SELECT C.* FROM StockToCategory STC 
INNER JOIN Category C ON STC.CategoryID = C.CategoryID 
WHERE STC.StockID = @StockID 

VSINNER JOIN vs EN

SELECT * FROM Category 
WHERE CategoryID IN 
    (SELECT CategoryID FROM StockToCategory WHERE StockID = @StockID) 

Ce qui est considéré comme le correct (syntaxiquement) et approche la plus performante et pourquoi?

La syntaxe dans le dernier exemple me semble plus logique mais mon hypothèse est que le JOIN sera plus rapide. J'ai regardé les plans de requête et n'ai pas pu déchiffrer quoi que ce soit à partir de ceux-ci.

Query Plan 1
Query Plan 2

+0

Si les deux peuvent exécuter, les deux sont syntaxiquement correct. Cela me semble être le problème classique des jointures par rapport aux sous-requêtes ... – BoltClock

+0

Bien noté, mais je suis sûr que les experts SQL ici diront que l'un est "plus" correct que l'autre. –

+1

Pourquoi ne pas mettre les deux requêtes dans une fenêtre de requête SSMS et les exécuter ensemble. Assurez-vous de "inclure le plan d'exécution réel" - SSMS affichera quelle requête prend combien de pour cent du temps d'exécution total. Si vous avez 50%: 50%, les deux sont à peu près égaux.Si l'on fait pire, SSMS montrera que très bien –

Répondre

10

Les deux syntaxes servent à des fins différentes. L'utilisation de la syntaxe Join suppose que vous voulez quelque chose à la fois de la table StockToCategory et de la catégorie. S'il existe plusieurs entrées dans la table StockToCategory pour chaque catégorie, les valeurs de la table Catégorie seront répétées. L'utilisation de la fonction IN présuppose que vous ne voulez que des éléments de la catégorie dont l'ID répond à certains critères. Si un CategoryId donné (en supposant qu'il s'agit du PK de la table Category) existe plusieurs fois dans la table StockToCategory, il ne sera retourné qu'une seule fois.

Dans votre exemple exact, ils produiront la même sortie mais IMO, la syntaxe ultérieure rend plus claire votre intention (ne voulant que des catégories).

Btw, une troisième syntaxe qui est similaire à l'aide de la fonction IN:

Select ... 
From Category 
Where Exists (
       Select 1 
       From StockToCategory 
       Where StockToCategory.CategoryId = Category.CategoryId 
        And StockToCategory.Stock = @StockId 
       ) 
+0

Pour cette variante, je dirais que "... EXISTS (SELECT * ...)" est une meilleure syntaxe. – Serguei

+3

+1 pour signaler que JOIN peut dupliquer des lignes de catégorie, * c'est la véritable différence entre ces requêtes. – Serguei

+0

Merci pour votre contribution :-) –

1

Syntaxiquement (sémantiquement aussi) ceux-ci sont à la fois correct. En termes de performances, ils sont effectivement équivalents, en fait je m'attendrais à ce que SQL Server génère les mêmes plans physiques pour ces deux requêtes.

+0

C'était mon premier instinct, mais ils ne le font pas! Mauvais poste le plan de requête en ligne afin que vous puissiez tous jeter un oeil ... –

+0

@Maxim: Pourriez-vous également poster les définitions de table? (y compris les indices, les clés étrangères). Quelle version de SQL Server génère également ces plans? – Serguei

0

T pense qu'il ya seulement deux façons de spécifier le même résultat souhaité.

0

pour SQLite

device_group_folders table contient 10 enregistrements

device_groups table contient ~ 100000 enregistrements

INNER JOIN: 31 ms

WITH RECURSIVE select_childs(uuid) AS (
SELECT uuid FROM device_group_folders WHERE uuid = '000B:653D1D5D:00000003' 
UNION ALL 
SELECT device_group_folders.uuid FROM device_group_folders INNER JOIN select_childs ON parent = select_childs.uuid 
) SELECT device_groups.uuid FROM select_childs INNER JOIN device_groups ON device_groups.parent = select_childs.uuid; 

OU 31 ms

WITH RECURSIVE select_childs(uuid) AS (
    SELECT uuid FROM device_group_folders WHERE uuid = '000B:653D1D5D:00000003' 
UNION ALL 
SELECT device_group_folders.uuid FROM device_group_folders INNER JOIN select_childs ON parent = select_childs.uuid 
) SELECT device_groups.uuid FROM select_childs, device_groups WHERE device_groups.parent = select_childs.uuid; 

EN < 1 ms

SELECT device_groups.uuid FROM device_groups WHERE device_groups.parent IN (WITH RECURSIVE select_childs(uuid) AS (
    SELECT uuid FROM device_group_folders WHERE uuid = '000B:653D1D5D:00000003' 
    UNION ALL 
    SELECT device_group_folders.uuid FROM device_group_folders INNER JOIN select_childs ON parent = select_childs.uuid 
) SELECT * FROM select_childs);