web-dev-qa-db-fra.com

SQL rejoint Vs SQL Subqueries (Performance)?

Je souhaite savoir si j'ai un rejoindre requête quelque chose comme ceci -

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id

et un sous-requête quelque chose comme ceci -

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept)

Quand je considère performance laquelle des deux requêtes serait plus rapide et pourquoi ?

Aussi, y a-t-il un moment où je devrais préférer l'un plutôt que l'autre?

Désolé si c'est trop trivial et demandé avant, mais je suis confus à ce sujet. En outre, il serait bon que vous puissiez me suggérer outils que je devrais utiliser pour mesurer les performances de deux requêtes. Merci beaucoup!

95
Vishal

J'attendrais que la première requête soit plus rapide, principalement parce que vous avez une équivalence et une jointure explicite. D'après mon expérience, IN est un opérateur très lent, car SQL l'évalue normalement comme une série de clauses WHERE séparées par "OR" (WHERE x=Y OR x=Z OR...).

Comme avec ALL THINGS SQL, votre kilométrage peut varier. La vitesse dépendra beaucoup des index (avez-vous des index sur les deux colonnes d'ID? Cela vous aidera beaucoup ...) entre autres choses.

Le seul moyen REAL de déterminer avec une certitude à 100% ce qui est plus rapide consiste à activer le suivi des performances (IO Statistics est particulièrement utile) et à exécuter les deux. Assurez-vous d'effacer votre cache entre les exécutions!

43
JNK

Eh bien, je crois que c’est une question "vieux mais or". La réponse est: "Cela dépend!". Les performances sont un sujet tellement délicat qu'il serait trop bête de dire: "N'utilisez jamais de sous-requêtes, joignez-vous toujours". Dans les liens suivants, vous trouverez quelques bonnes pratiques de base que j’ai trouvées très utiles: ici 1ici 2ici

J'ai une table avec 50000 éléments, le résultat que je recherchais était de 739 éléments.

Ma requête au début était la suivante:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND p.anno = (
    SELECT MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p2.fixedId = p.fixedId 
)

et il a fallu 7.9s pour exécuter.

Ma question enfin est la suivante:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN
(
    SELECT p2.fixedId, MAX(p2.anno)
    FROM prodotto p2
    WHERE p.azienda_id = p2.azienda_id
    GROUP BY p2.fixedId
)

et il a fallu 0.0256s

Bon SQL, bon.

30
linuxatico

Commencez par examiner les plans d'exécution pour voir les différences dans la façon dont le serveur SQl les interprétera. Vous pouvez également utiliser Profiler pour exécuter les requêtes plusieurs fois et obtenir la différence.

Je ne m'attendrais pas à ce que ceux-ci soient si horriblement différents, où vous pouvez obtenir de réels gains en performances en utilisant des jointures au lieu de sous-requêtes, c'est lorsque vous utilisez des sous-requêtes corrélées.

EXISTS est souvent préférable à l’un ou l’autre de ces deux scénarios. Lorsque vous parlez de jointures gauches là où vous voulez utiliser tous les enregistrements qui ne se trouvent pas dans la table des jointures gauche, NOT EXISTS est souvent un meilleur choix.

10
HLGEM

Les performances sont basées sur la quantité de données que vous exécutez sur ...

Si c'est moins de données autour de 20k. JOIN fonctionne mieux.

Si les données ressemblent plus à 100k +, alors IN fonctionne mieux.

Si vous n’avez pas besoin des données de l’autre table, IN est bon, mais il vaut toujours mieux choisir EXISTS.

Tous ces critères que j'ai testés et les tables ont des index appropriés.

8
JP Emvia

Les deux requêtes peuvent ne pas être sémantiquement équivalentes. Si un employé travaille pour plus d'un service (possible dans l'entreprise pour laquelle je travaille; certes, votre table n'est pas entièrement normalisée), la première requête renvoie des lignes en double, alors que la seconde ne le fait pas. Pour que les requêtes soient équivalentes dans ce cas, le mot clé DISTINCT doit être ajouté à la clause SELECT, ce qui peut avoir un impact sur les performances.

Notez qu'il existe une règle empirique qui stipule qu'une table doit modéliser une entité/classe ou une relation entre entités/classes mais pas les deux. Par conséquent, je vous suggère de créer une troisième table, par exemple OrgChart, afin de modéliser la relation entre les employés et les services.

4
onedaywhen

Je sais que c’est un article ancien, mais j’estime que c’est un sujet très important, en particulier aujourd’hui où nous avons plus de 10 millions d’enregistrements et parlons de téraoctets de données.

Je vais aussi pondérer avec les observations suivantes. J'ai environ 45 millions d'enregistrements dans ma table ([données]) et environ 300 enregistrements dans ma table [chats]. J'ai une longue indexation pour toutes les questions dont je vais parler.

Considérons l'exemple 1:

UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid

versus exemple 2:

UPDATE d set category = (SELECT TOP(1) c.categoryname FROM [cats] c where c.id = d.catid)
FROM [data] d

L'exemple 1 prenait environ 23 minutes à courir. Exemple 2 a pris environ 5 minutes.

Je conclus donc que la sous-requête dans ce cas est beaucoup plus rapide. Bien sûr, gardez à l’esprit que j’utilise des disques SSD M.2 capables d’e/s à 1 Go/s (octets et non bits), mes index sont donc très rapides aussi. Donc, cela peut affecter les vitesses aussi dans votre cas

S'il s'agit d'un nettoyage ponctuel de données, il est probablement préférable de le laisser fonctionner et de le terminer. J'utilise TOP (10000) et vois combien de temps cela prend et que je multiplie par le nombre d'enregistrements avant de lancer la grande requête.

Si vous optimisez des bases de données de production, je vous suggère fortement de pré-traiter les données, c’est-à-dire d’utiliser des déclencheurs ou des courtiers de travaux pour asynchroniser les enregistrements de mise à jour, afin que l’accès en temps réel récupère les données statiques.

3
Arvin Amir

La performance devrait être la même; il est bien plus important d’appliquer les index et la classification appropriés sur vos tables (il existe de bonnes ressources sur ce sujet).

(Edité pour refléter la question mise à jour)

3
Lucero

Vous pouvez utiliser un plan Explain pour obtenir une réponse objective.

Pour votre problème, n filtre Exists serait probablement le plus rapide.

0
Snekse