CodeGym /Cours /SQL SELF /Équilibre entre normalisation et performance

Équilibre entre normalisation et performance

SQL SELF
Niveau 26 , Leçon 3
Disponible

Équilibre entre normalisation et performance

Quand on normalise les données à fond, chaque table devient super compacte et chaque info respecte un seul principe. Mais pour faire des vraies requêtes (genre "Quels étudiants sont inscrits au cours SQL ?"), il faut souvent faire des JOIN sur plein de tables. Plus il y a de tables, plus les requêtes deviennent galère, et plus le système "rame à la pelle".

Tu connais sûrement déjà les JOIN grâce aux cours précédents. Voilà un exemple de requête qu’on peut avoir avec une base bien normalisée :

SELECT students.name, courses.title
FROM students
JOIN enrollments ON students.id = enrollments.student_id
JOIN courses ON enrollments.course_id = courses.id
WHERE courses.title = 'SQL';

Ça a l’air simple, mais sous le capot le serveur bosse comme un dingue : il lit chaque table, fait les jointures, filtre... Et si les tables sont énormes ? Logiquement, la perf va chuter.

La guerre : normalisation vs vitesse

Heureusement (ou pas ?), dans la vraie vie, les bases de données c’est toujours un compromis. Une normalisation totale garantit l’intégrité des données, mais ralentit les requêtes complexes. Si ta base sert surtout à de l’analytics ou des rapports, parfois il vaut mieux la dénormaliser. C’est comme remplacer 10 petites boîtes par un gros coffre : tu récupères les données plus vite, mais tout reclasser devient plus chiant.

Quand est-ce qu’on peut "relâcher" la normalisation ?

Il y a des cas où la dénormalisation est plus cool :

Agrégats utilisés tout le temps

Par exemple, imagine que le système fait tous les jours des requêtes pour compter le nombre d’étudiants par cours. En structure normalisée, il faut faire des JOIN et COUNT() à chaque fois. À la place, tu peux ajouter une colonne student_count dans la table "Courses", mise à jour automatiquement quand tu ajoutes/supprimes des lignes.

-- Colonne dénormalisée
UPDATE courses
SET student_count = (
    SELECT COUNT(*)
    FROM enrollments
    WHERE enrollments.course_id = courses.id
);

Rapports générés tout le temps

Si ton client veut chaque jour un rapport "Qui a acheté quoi, où et quand ?", c’est plus simple de garder une table dénormalisée avec des lignes prêtes du style "Nom du client, produit, date". La table sera plus grosse, mais tu gagnes en rapidité.

Beaucoup de lectures, peu d’écritures

Quand la base sert surtout à lire (genre analytics), tu peux sacrifier la normalisation pour la vitesse.

Réduire les jointures dans les relations complexes

Si les relations entre tables sont imbriquées (nested) et que les JOIN deviennent l’enfer, enlève quelques niveaux de normalisation.

Exemple : comment la dénormalisation accélère les choses ?

On a des tables normalisées pour un e-commerce :

Table products Table orders Table order_items
id id id
name date order_id
price customer_id product_id
quantity

Chaque commande (orders) contient des lignes de commande (order_items). Calculons combien le shop a gagné :

SELECT SUM(order_items.quantity * products.price) AS total_revenue
FROM order_items
JOIN products ON order_items.product_id = products.id;

La jointure entre order_items et products va ralentir la requête si t’as beaucoup de données.

Structure dénormalisée

Maintenant, imagine qu’on ajoute une colonne "en trop" total_price dans order_items (dénormalisation) :

Table order_items
id
order_id
product_id
quantity
total_price

La requête devient alors triviale :

SELECT SUM(total_price) AS total_revenue
FROM order_items;

On évite le JOIN, donc c’est plus rapide.

Exercice pratique : optimisation de la base "Ventes"

Donné : tables normalisées

Table products Table sales
id id
name product_id
price date
quantity

Objectif : accélérer les requêtes du genre "Combien on a gagné sur chaque produit ?".

Étape 1 : ajoute une colonne total_price dans la table sales :

ALTER TABLE sales ADD COLUMN total_price NUMERIC;

Étape 2 : remplis cette colonne avec les données existantes :

UPDATE sales
SET total_price = quantity * (
    SELECT price
    FROM products
    WHERE products.id = sales.product_id
);

Étape 3 : fais des requêtes plus rapides :

SELECT product_id, SUM(total_price) AS total_revenue
FROM sales
GROUP BY product_id;

Mais ! La dénormalisation a un prix

Tu te doutes bien que "plus rapide" ne veut pas toujours dire "mieux". Avec la dénormalisation, tu rencontres des soucis :

Stockage redondant

La colonne total_price c’est une copie des données, donc ça prend plus de place.

Mise à jour plus compliquée

Si le prix d’un produit change dans la table products, il faut mettre à jour la colonne total_price à la main. Ça peut créer des incohérences.

Anomalies à l’insertion, mise à jour et suppression

Les infos peuvent vite "se désynchroniser" si tu oublies de mettre à jour les données dénormalisées. Par exemple, si le prix d’un produit change, ce n’est pas automatique.

Équilibre : comment trouver le juste milieu ?

Choisis ce qui compte le plus : la perf ou la structure ? Si ta base est surtout lue, adapte-toi aux requêtes.

Ajoute de la dénormalisation là où c’est vraiment utile. Genre, seulement pour les chiffres clés et les rapports.

Automatise la mise à jour des données dénormalisées. Utilise des triggers ou des jobs pour éviter les incohérences.

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION