Colonne en double pour des requêtes plus rapides?


30

Le titre n'a pas trop de sens, mais je ne pouvais pas penser à un meilleur titre pour ce problème.

J'ai les tableaux suivants

Projets

  • identifiant
  • prénom

Les clients

  • identifiant
  • id_project
  • prénom

Paiements

  • identifiant
  • id_customer
  • rendez-vous amoureux
  • somme

Lorsqu'un utilisateur entre dans le système, il aura accès à un certain projet. Maintenant, je veux lister tous les paiements pour ce projet, et ça devrait être assez facile:

SELECT FROM payments where id_customer in (SELECT id from customers where id_project = 5)

Ma question est: s'il n'est pas préférable d'ajouter une colonne id_project à la table des paiements de cette façon, les requêtes seront plus faciles et plus rapides.


1
la requête n'est donc pas un problème pour les SGBDR modernes (ou mieux, utilisez join).
garik

4
D'accord, obtenez un plan de requête pour sous-sélectionner ou rejoindre et voyez lequel est le meilleur
Gaius

1
Je pense que ce SO poste est intéressant de regarder, depuis @igor mentionné sur l' utilisation de JOIN ou IN
CoderHawk

Réponses:


52

Il semble que vous vous demandiez si la dénormalisation a un sens.

La dénormalisation est le processus consistant à tenter d'optimiser les performances de lecture d'une base de données en ajoutant des données redondantes ou en regroupant des données. Dans certains cas, la dénormalisation permet de masquer les inefficacités inhérentes aux logiciels de bases de données relationnelles. Une base de données relationnelle normalisée impose une lourde charge d'accès sur le stockage physique des données même si elle est bien réglée pour de hautes performances.

La réponse est toujours "ça dépend", alors voici ma règle d'or:

Si ...

  • la quantité de données n'est pas grande
  • vous ne faites pas déjà une tonne de jointures
  • et / ou les performances de la base de données ne sont pas actuellement un goulot d'étranglement

puis restez normalisé . Oui, la dénormalisation est plus rapide, mais cela signifie également que vous avez des données redondantes dans le système - des données qui doivent être maintenues et synchronisées. Il n'y a plus "une seule source" pour ces données, mais plusieurs sources qui peuvent dévier. Cela est risqué au fil du temps, vous ne devriez donc pas le faire à moins d'avoir de très bonnes raisons de le faire, étayé par certains critères de référence.

Je ne dénormaliserais que quand ...

  • la quantité de données est très importante
  • les jointures sont chères et vous devez en faire beaucoup pour obtenir des requêtes même triviales
  • les performances de la base de données sont un goulot d'étranglement et / ou vous voulez aller aussi vite que possible

Les jointures sont très rapides sur du matériel moderne, mais elles ne sont jamais gratuites.


9

Il serait préférable de réécrire la requête comme suit:

SELECT payments.*
FROM   customers
JOIN   payments 
ON     payments.id_customer = customers.id
WHERE  customers.id_project = 5

Bien que cela semble moins concis et qu'un bon planificateur de requêtes verra ce que vous essayez de faire et exécutera votre sous-requête corrélée comme la jointure ci-dessus à la place, un mauvais planificateur de requêtes peut finir par faire un balayage d'index de payments.id_customer(en supposant que vous avez un index pertinent ) (ou pire, l'analyse de table) au lieu de faire les choses de la manière la plus efficace. Même un bon planificateur de requêtes peut ne pas voir l'optimisation si l'arrangement de cette requête est enveloppé dans quelque chose de plus compliqué. Exprimer la relation sous la forme d'une jointure plutôt que d'une sous-requête peut faire plus de différence que de modifier votre structure de données.

Comme Jeff le dit, toute dénormalisation doit être considérée avec soin - elle peut apporter des gains de performances faciles, en particulier à certaines fins de génération de rapports, mais peut entraîner des incohérences en raison de bogues dans la logique métier de support.

En remarque: de toute évidence, je ne connais pas votre entreprise, donc je pourrais manquer quelque chose, mais vos relations avec la table me semblent étranges. Ils impliquent que vous ne pouvez jamais avoir plus d'un projet avec le même client, ce qui n'est généralement pas vrai dans mon expérience, au moins sur une longue période.

customer     project      payment
--------     --------     -------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer     

ou si elle est moins normalisée (bien que je doute que cela soit nécessaire):

customer     project      payment
--------     --------     --------
                          pa_id
             pr_id    <-- payment
cu_id    <-- customer 
           `------------- customer    

Bien sûr, cela exclut toujours la possibilité d'un projet commun avec deux clients ...


3
Première règle de performance: ne jamais utiliser * en production!
Brian Ballsun-Stanton

@Brian: point très valable. Et ainsi que les implications potentielles en termes de performances en évitant * dans les clauses select, cela évite également les problèmes avec l'ordre des colonnes dans les vues sur vue dans MSSQL si sys.depends devient incontrôlable car DROP VIEW+ CREATE VIEWest utilisé à la place de ALTER VIEW.
David Spillett

@Brian j'ai mis * pour faciliter l'écriture.
Gabriel Solomon

Le projet est davantage pensé comme une application indépendante avec son domaine on et appartient à différents clients, donc un client ne peut pas avoir le même compte sur différents projets
Gabriel Solomon

4

Dans certaines bases de données, vous avez la possibilité de créer des "vues matérialisées" au lieu de VUES complexes avec une grande quantité de données, basées sur une requête complexe. Cela peut être utilisé pour éviter la dénormalisation dans un système d'application développé historiquement. Si vous décidez d'utiliser " Vues matérialisées ", vous devez avoir une idée claire des méthodes de rafraîchissement et de la quantité de stockage qui sera utilisée par la vue matérialisée ...

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.