web-dev-qa-db-fra.com

Quand utiliser des sous-requêtes SQL par rapport à une jointure standard?

Je travaille sur la réécriture de certaines requêtes SQL mal écrites et elles utilisent trop les sous-requêtes. Je recherche les meilleures pratiques concernant l'utilisation des sous-requêtes.

Toute aide serait appréciée.

35
Brad Krusemark

Les sous-requêtes sont généralement correctes sauf si elles sont sous-requêtes dépendantes (également appelées sous-requêtes corrélées ). Si vous utilisez uniquement des sous-requêtes indépendantes et qu'elles utilisent des index appropriés, elles doivent s'exécuter rapidement. Si vous avez une sous-requête dépendante, vous pouvez rencontrer des problèmes de performances car une sous-requête dépendante doit généralement être exécutée une fois pour chaque ligne de la requête externe. Donc, si votre requête externe a 1000 lignes, la sous-requête sera exécutée 1000 fois. D'un autre côté, une sous-requête indépendante ne doit généralement être évaluée qu'une seule fois.

Si vous n'êtes pas sûr de ce que signifie une sous-requête dépendante ou indépendante, voici une règle de base - si vous pouvez prendre la sous-requête, la supprimer de son contexte, l'exécuter et obtenir un jeu de résultats, c'est un independent subquery.

Si vous obtenez une erreur de syntaxe car elle fait référence à certaines tables en dehors de la sous-requête, alors c'est un dependent subquery.

La règle générale comporte bien sûr quelques exceptions. Par exemple:

  • De nombreux optimiseurs peuvent prendre une sous-requête dépendante et trouver un moyen de l'exécuter efficacement en tant que JOIN. Par exemple, une requête NOT EXISTS peut entraîner un plan de requête ANTI JOIN, elle ne sera donc pas nécessairement plus lente que l'écriture de la requête avec un JOIN.
  • MySQL a un bug où une sous-requête indépendante à l'intérieur d'une expression IN est incorrectement identifiée comme une sous-requête dépendante et donc un plan de requête sous-optimal est utilisé. Cela est apparemment corrigé dans les toutes dernières versions de MySQL.

Si les performances sont un problème, mesurez vos requêtes spécifiques et voyez ce qui vous convient le mieux.

52
Mark Byers

Il n'y a pas de solution miracle ici. Chaque utilisation doit être évaluée de manière indépendante. Il y a des cas où les sous-requêtes corrélées sont tout simplement inefficaces, celle-ci ci-dessous est mieux écrite en tant que JOIN

select nickname, (select top 1 votedate from votes where user_id=u.id order by 1 desc)
from users u

D'un autre côté, les requêtes EXISTS et NOT EXISTS l'emporteront sur JOINs.

select ...
where NOT EXISTS (.....)

Est normalement plus rapide que

select ...
FROM A LEFT JOIN B
where B.ID is null

Pourtant, même ces généralisations peuvent être fausses pour tout schéma particulier et distribution de données.

6
RichardTheKiwi

Malheureusement, la réponse dépend grandement du serveur SQL que vous utilisez. En théorie, les jointures sont meilleures du point de vue de la théorie relationnelle pure. Ils laissent le serveur faire ce qu'il faut sous le capot et leur donne plus de contrôle et donc au final peut être plus rapide. Si le serveur est bien implémenté. En pratique, certains serveurs SQL fonctionnent mieux si vous l'incitez à optimiser leurs requêtes via des sous-requêtes et autres.

4
Wes Hardaker