La normalisation règle certains soucis, mais parfois elle en crée d'autres, surtout côté perf. Aujourd'hui, on va t'ouvrir les portes de l'art sombre (et parfois lumineux) — la dénormalisation. Ouais, tu peux casser les règles de la normalisation... mais faut le faire intelligemment !
La dénormalisation, c'est le process inverse de la normalisation. Si la normalisation découpe les tables en entités logiques séparées pour minimiser la redondance, la dénormalisation, elle, regroupe les données pour booster les perfs. On l'utilise souvent quand, sous grosse charge et avec des requêtes complexes fréquentes, les multiples jointures commencent à ralentir le système.
On peut dire que la dénormalisation, c'est un compromis entre la pureté des données et la vitesse d'exécution des requêtes.
Quand utiliser la dénormalisation ?
Comme pour n'importe quel outil, faut savoir quand la dénormalisation est pertinente. On l'utilise dans les cas suivants :
Les requêtes fréquentes deviennent lentes. Quand un système sous grosse charge exécute souvent les mêmes requêtes (genre des rapports ou des agrégats), les jointures multiples peuvent prendre un temps fou. La dénormalisation permet de réduire le nombre de ces jointures.
Tâches analytiques et stats. Dans les systèmes analytiques (genre BI — Business Intelligence), on a souvent besoin d'analyser de gros volumes de données. Dans ces cas-là, la dénormalisation accélère le traitement grâce à des données "préparées".
Requêtes complexes. Si pour une requête tu dois joindre cinq, dix ou même plus de tables, ça peut grave ralentir la base. La dénormalisation simplifie la structure des requêtes.
Le nombre de jointures dépasse le bon sens. Si tu te retrouves avec des requêtes qui joignent 25 tables en
JOIN, c'est peut-être le moment de revoir ta stratégie.
Exemples de dénormalisation
Exemple 1 : Boutique en ligne. Dans une base normalisée d'une boutique en ligne, on pourrait avoir ces tables :
customers— données sur les clients.orders— infos sur les commandes.products— données sur les produits.order_items— articles dans une commande.
La requête pour choper les infos pourrait ressembler à ça :
SELECT
c.customer_name,
o.order_date,
p.product_name,
oi.quantity
FROM
customers c
JOIN
orders o ON c.customer_id = o.customer_id
JOIN
order_items oi ON o.order_id = oi.order_id
JOIN
products p ON oi.product_id = p.product_id
WHERE
c.customer_id = 42;
Mais si ta boutique gère des centaines de milliers de commandes par jour ? Cette requête va devenir super lente à cause de toutes ces jointures.
Solution : dénormalisation.
On va créer une table pour les infos utilisées souvent :
CREATE TABLE order_summary AS
SELECT
c.customer_id,
c.customer_name,
o.order_id,
o.order_date,
p.product_id,
p.product_name,
oi.quantity
FROM
customers c
JOIN
orders o ON c.customer_id = o.customer_id
JOIN
order_items oi ON o.order_id = oi.order_id
JOIN
products p ON oi.product_id = p.product_id;
Maintenant, pour récupérer les données, on fait juste une requête sur order_summary :
SELECT * FROM order_summary WHERE customer_id = 42;
Exemple 2 : Système d'analytics. Imaginons que tu bosses sur une base pour une boîte qui vend des billets pour des événements. Il y a les tables :
events— infos sur les événements.sales— données sur les ventes de billets.
Si les analystes veulent un rapport sur le revenu moyen par billet pour tous les événements, la structure normalisée t'oblige à faire une requête d'agrégation à chaque fois :
SELECT
e.event_name,
AVG(s.price) AS avg_ticket_price
FROM
events e
JOIN
sales s ON e.event_id = s.event_id
GROUP BY
e.event_name;
Cette requête peut être bien lente, surtout si chaque vente représente des millions de lignes.
Solution : dénormalisation. On crée une table séparée avec les données agrégées :
CREATE TABLE event_summary AS
SELECT
e.event_id,
e.event_name,
COUNT(s.sale_id) AS ticket_count,
SUM(s.price) AS total_revenue,
AVG(s.price) AS avg_ticket_price
FROM
events e
JOIN
sales s ON e.event_id = s.event_id
GROUP BY
e.event_id, e.event_name;
Maintenant, les rapports tournent plus vite sur le niveau agrégé :
SELECT
event_name,
avg_ticket_price
FROM
event_summary;
Conséquences de la dénormalisation
La dénormalisation, ouais, ça peut accélérer les requêtes, mais c'est pas une baguette magique qui règle tout. Voilà à quoi tu peux t'attendre si tu te lances là-dedans.
Premièrement — duplication des données. Quand la même info est stockée à plusieurs endroits, la taille de la base grimpe vite, et ça devient plus galère à gérer.
Deuxièmement — mettre à jour les données devient plus compliqué. Imagine, t'as les infos d'un client dans la table customers, et aussi une copie dans order_summary. Si le client change de nom ou d'adresse, faut pas oublier de mettre à jour aux deux endroits. Si tu rates un spot — bam, erreur, les données sont plus synchro.
Troisièmement — à cause de cette redondance, tu peux vite t'embrouiller et faire des boulettes. C'est comme avec plusieurs versions d'un même doc — parfois, tu sais plus laquelle est la bonne.
Et enfin, maintenir et faire évoluer une telle base, c'est plus chaud. Tu devras écrire des triggers ou des scripts spéciaux pour garder toutes les copies synchro. C'est du taf en plus pour les devs.
En gros, la dénormalisation, c'est un outil à utiliser avec la tête, en connaissant bien les avantages et les inconvénients.
GO TO FULL VERSION