101 votes

Pourquoi les jointures sont-elles inefficaces lorsqu'on considère la scalabilité ?

Pourquoi les jointures sont-elles mauvaises ou « lentes » ? Je sais que j'ai entendu ça plus d'une fois. J'ai trouvé cette citation

Le problème est que les jointures sont relativement lentes, surtout avec de très grands ensembles de données, et si elles sont lentes, votre site web est lent. Il prend beaucoup de temps pour obtenir tous ces morceaux d'information séparés du disque et les rassembler à nouveau.

source

J'ai toujours pensé qu'elles étaient rapides, surtout lorsqu'on recherche une PK. Pourquoi sont-elles 'lentes' ?

111voto

Joel Coehoorn Points 190579

L'évolutivité consiste à précalculer (mettre en cache), à répartir ou à simplifier le travail répété au strict nécessaire, afin de minimiser l'utilisation des ressources par unité de travail. Pour bien évoluer, vous ne faites rien en volume si ce n'est nécessaire, et vous vous assurez d'effectuer les tâches réellement nécessaires de la manière la plus efficace possible.

Dans ce contexte, il est évident que joindre deux sources de données distinctes est relativement lent, du moins par rapport à ne pas les joindre, car c'est un travail que vous devez effectuer en direct au moment où l'utilisateur en fait la demande.

Mais souvenez-vous que l'alternative est de ne plus disposer du tout de deux morceaux de données distincts; vous devez mettre les deux points de données disparates dans le même enregistrement. Vous ne pouvez pas combiner deux éléments de données différents sans conséquence quelque part, donc assurez-vous de comprendre le compromis.

La bonne nouvelle est que les bases de données relationnelles modernes sont bonnes pour les jointures. Vous ne devriez pas vraiment considérer les jointures comme lentes avec une bonne base de données utilisée correctement. Il existe plusieurs façons favorables à l'évolutivité de rendre les jointures brutes beaucoup plus rapides :

  • Joindre sur une clé substitutive (colonne autonumérisée/identité) plutôt que sur une clé naturelle. Cela signifie des comparaisons plus petites (et donc plus rapides) pendant l'opération de jointure
  • Index
  • Vues matérialisées/indexées (pensez à cela comme une jointure précalculée ou une dénormalisation gérée)
  • Colonnes calculées. Vous pouvez l'utiliser pour hacher ou précalculer les colonnes clés d'une jointure, de sorte que ce qui aurait été une comparaison compliquée pour une jointure est maintenant beaucoup plus petite et potentiellement pré-indéxé.
  • Partitions de table (aide avec de grands ensembles de données en répartissant la charge sur plusieurs disques, ou limitant ce qui aurait pu être un balayage de table à un balayage de partition)
  • OLAP (précalcule les résultats de certains types de requêtes/jointures. Ce n'est pas tout à fait vrai, mais vous pouvez le considérer comme une dénormalisation générique)
  • Réplication, groupes de disponibilité, envoi de journaux, ou d'autres mécanismes permettant à plusieurs serveurs de répondre aux requêtes de lecture pour la même base de données, et ainsi répartir votre charge de travail entre plusieurs serveurs.
  • Utilisation d'une couche de mise en cache comme Redis pour éviter de rerun les requêtes nécessitant des jointures complexes.

J'irais même jusqu'à dire que la principale raison pour laquelle les bases de données relationnelles existent est de vous permettre de réaliser des jointures efficacement*. Ce n'est certainement pas uniquement pour stocker des données structurées (vous pourriez le faire avec des structures de fichiers plats comme csv ou xml). Quelques-unes des options que j'ai énumérées vous permettront même de construire entièrement votre jointure à l'avance, de sorte que les résultats soient déjà prêts avant que vous ne lanciez la requête - tout comme si vous aviez dénormalisé les données (avec des opérations d'écriture plus lentes, il est vrai).

Si vous avez une jointure lente, vous n'utilisez probablement pas votre base de données correctement.

La dénormalisation ne devrait être effectuée qu'après l'échec de ces autres techniques. Et la seule façon de véritablement juger de "l'échec" est de définir des objectifs de performance significatifs et de mesurer par rapport à ces objectifs. Si vous n'avez pas mesuré, il est trop tôt pour même penser à la dénormalisation.


* C'est-à-dire exister en tant qu'entités distinctes des simples collections de tables. Une raison supplémentaire pour une véritable base de données relationnelle est l'accès concurrentiel sécurisé.

14 votes

Les index devraient probablement être en haut de la liste. Beaucoup (tousse) de développeurs semblent les oublier lorsqu'ils testent sur un petit jeu de données, puis mettent la base de données à genoux en production. J'ai vu des requêtes s'exécuter jusqu'à 100 000 fois plus rapidement simplement en ajoutant des index. Et ce sont des index arbitraires sans même faire d'analyse approfondie des données pour déterminer le meilleur mix pour les correspondances de préfixe le plus à gauche.

0 votes

Je pense avoir bien ordonné la liste - la plupart des développeurs font déjà le premier élément, et donc les index sont le premier élément sur lequel ils devront apporter des modifications.

0 votes

Dans votre troisième élément, vous mentionnez des "vues materialized/indexées". Parlez-vous de vues SQL régulières ou autre chose?

29voto

Tendayi Mawushe Points 10335

Les jointures peuvent être plus lentes que de les éviter via la dénormalisation, mais si elles sont utilisées correctement (en joignant sur des colonnes avec des index appropriés, etc.), elles ne sont pas intrinsèquement lentes.

La dénormalisation est l'une des nombreuses techniques d'optimisation que vous pouvez envisager si votre schéma de base de données bien conçu présente des problèmes de performances.

2 votes

...sauf dans MySQL, qui semble avoir des problèmes de performance avec un grand nombre de jointures, peu importe l'apparence de vos index. Ou du moins, c'était le cas par le passé.

2 votes

Point pris, s'il existe des problèmes connus avec le SGBD spécifique (et peut-être même la version), alors ce conseil peut avoir du sens, mais en tant que conseil général, il est assez trompeur si vous utilisez une base de données relationnelle. Cela dit, les mécanismes de stockage non relationnels deviennent de plus en plus populaires Amazon's SimpleDB et CouchDB (couchdb.apache.org) en sont des exemples. Si vous êtes mieux servi en laissant le modèle relationnel derrière vous, vous devriez probablement laisser également derrière vous les produits qui sont optimisés pour celui-ci et chercher d'autres outils.

14voto

Andrey Points 36869

L'article dit qu'ils sont lents par rapport à l'absence de jointures. Cela peut être réalisé avec la dénormalisation. Il y a donc un compromis entre la vitesse et la normalisation. N'oubliez pas l'optimisation prématurée aussi :)

0 votes

Même si ce n'est pas une règle stricte, si vous faites une jointure sur une table, MySQL pourrait utiliser un index pour effectuer cette jointure - cette jointure d'index pourrait élaguer de nombreuses lignes, ainsi qu'un autre index pour toute clause WHERE sur les tables. Si vous ne faites pas de jointure, MySQL utilisera généralement un seul index (qui pourrait ne pas être le plus efficace), peu importe la manière dont votre clause WHERE est formée.

10voto

HLGEM Points 54641

Les personnes avec des bases de données de taille téraoctet utilisent encore des jointures, si elles peuvent les faire fonctionner en termes de performances, vous pouvez aussi le faire.

Il existe de nombreuses raisons de ne pas dénormaliser. Tout d'abord, la vitesse des requêtes de sélection n'est pas la seule ou même la principale préoccupation des bases de données. L'intégrité des données est la première préoccupation. Si vous dénormalisez, vous devez mettre en place des techniques pour maintenir les données dénormalisées lorsque les données parentales changent. Donc admettons que vous décidiez de stocker le nom du client dans toutes les tables au lieu de joindre à la table client sur le client_Id. Maintenant, lorsque le nom du client change (il y a une chance de 100% que certains noms de clients changeront avec le temps), vous devez maintenant mettre à jour tous les enregistrements enfants pour refléter ce changement. Si vous faites cela avec une mise à jour en cascade et que vous avez un million d'enregistrements enfants, à quelle vitesse pensez-vous que cela va se passer et combien d'utilisateurs vont souffrir de problèmes de verrouillage et de retards dans leur travail pendant que cela se produit? De plus, la plupart des personnes qui dénormalisent parce que les "jointures sont lentes" ne connaissent pas suffisamment les bases de données pour s'assurer correctement que leur intégrité des données est protégée et finissent souvent avec des bases de données contenant des données inutilisables en raison d'une intégrité si mauvaise.

La dénormalisation est un processus complexe qui nécessite une compréhension approfondie des performances et de l'intégrité de la base de données pour être réalisée correctement. Ne tentez pas de dénormaliser à moins d'avoir un tel expertise en interne.

Les jointures sont assez rapides si vous faites plusieurs choses. Utilisez d'abord une clé de substitution, une jointure de type entier est presque toujours la jointure la plus rapide. Deuxièmement, indexez toujours la clé étrangère. Utilisez des tables dérivées ou des conditions de jointure pour créer un ensemble de données plus petit sur lequel filtrer. Si vous avez une base de données très complexe et volumineuse, alors engagez un professionnel de la base de données avec de l'expérience en partitionnement et en gestion de bases de données énormes. Il existe de nombreuses techniques pour améliorer les performances sans abandonner les jointures.

Si vous avez juste besoin de capacité de requête, alors vous pouvez concevoir un entrepôt de données qui peut être dénormalisé et est peuplé via un outil ETL (optimisé pour la vitesse) et non par une saisie de données utilisateur.

7voto

Quassnoi Points 191041

Les jointures peuvent être lentes si de grandes portions d'enregistrements de chaque côté doivent être analysées.

Comme ceci:

SELECT  SUM(transaction)
FROM    customers
JOIN    accounts
ON      account_customer = customer_id

Même si un index est défini sur account_customer, tous les enregistrements de ce dernier doivent quand même être analysés.

Pour la liste de requête suivante, les optimiseurs corrects n'envisageront probablement pas même le chemin d'accès de l'index, faisant plutôt un HASH JOIN ou un MERGE JOIN.

Notez que pour une requête de ce type:

SELECT  SUM(transaction)
FROM    customers
JOIN    accounts
ON      account_customer = customer_id
WHERE   customer_last_name = 'Stellphlug'

la jointure sera très probablement rapide: d'abord, un index sur customer_last_name sera utilisé pour filtrer tous les Stellphlug (qui ne sont bien sûr pas très nombreux), puis un scan d'index sur account_customer sera effectué pour chaque Stellphlug afin de trouver ses transactions.

Malgré le fait qu'il puisse y avoir des milliards d'enregistrements dans accounts et customers, seulement quelques-uns devront en réalité être analysés.

0 votes

Mais il est difficile de l'éviter. concevez votre application de sorte que ce genre de requêtes ne soit pas exécuté trop souvent.

1 votes

Si un index est défini sur comptes (client_compte), la plupart des SGBDR utiliseraient cet index pour déterminer exactement quelles lignes de la base de données clients doivent être scannées.

0 votes

Oui, mais ce n'est pas une opération bon marché de toute façon. vous pouvez stocker la somme dans un champ et le mettre à jour à chaque transaction.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X