Databases: Efficient Denormalization with Views
By Steve Schnepp on Tuesday, 2 June 2009, 08:00 - database - Permalink
Everyone is unanimous that database normalization is considered a Good Thing.
But it usually comes with a cost : writing queries can be very tedious since you always have to join many tables together to be able to retrieve useful human data from all those reference tables.
On the other side, to denormalize is sometimes seen as a way to :
- optimize development : you do not need to write (and debug) complex queries since all the data is nicely located in the same table
- optimize performance : the data has a better locality (no need to fetch or compute data from elsewhere). You can even pre-compute order totals[1].
Denormalize correctly is quite difficult since one change snowballs in multiple updates to keep the redundant data coherent. It is therefore usually done on the application side with ready-to-use ORM frameworks. But managing it at the application level comes with an ugly cost : it has to be reimplemented over and over each time the application switches technology, version or when a new application is connecting to the database.
In almost every programming language, code reuse is encouraged. Here, at the database level, we can also apply the same principles, and use views to transparently present a denormalized API (read tables) on a more normalized schema.
The main points are :
- Views are the main code reuse vector at the database level. Current database usually correctly optimize (by rewrite and recombination) the simple queries so that performance is on par with a hand crafted query that doesn't use the views
- Sometime even faster since the data is nicely organized, so there is much less data to transfer, and I/O bandwidth is a usual suspect.
- The application part doesn't even need to know that normalization happens under-hood since updates to views are possible in many modern RDMs with the @@INSTEAD OF@@ trigger (or something equivalent).
- Theses updates can be created with Materialized views are a step even further on the denormalizing road, since it provides the common benefits of denormalize without the implementation caveats. We can even hand-craft these Materialized views directly in an aggregation table in order to have the space benefits of normalisation and the performance benefits of denormalization.
So, nothing stops you from normalizing at will, and denormalizing when needed. Where to put the cursor is yours to decide, but moving it afterwards is finally easier that what is commonly admited.
Notes
[1] That article also explains why denormalization maintenance must stay at the database level with a very interesting metaphor
Comments
Que dire sinon que tu parles d'or ? Je soufre actuellement (et le client paye très cher au final) à cause d'une application dénormalisée à mort faite par des gens qui doivent raisonner encore en fichiers plats et en Cobol.
Ajoutons que stocker contraintes, vues utilitaires, même logique fonctionnelle en base permet de garantir la cohérence contre toutes les attaques contre la cohérence de la base (du point de vue du DBA) : développeurs indisciplinés, doc pas claire, erreurs humaines, sous-traitance, stagiaires...
La dénormalisation doit être réservée aux cas extrêmes, et comme tu dis, entre les vues simples et les vues matérialisées, on doit pouvoir simplifier le développement. Attention, ces vues à mon sens ne doivent pas contenir de logique fonctionnelle précise sinon on duplique ce qui existe ailleurs dans l'appli (sauf à réutiliser, disons, des fonctions stockées fournies par cet appli) ; je n'aime que les vues qui font des jointures naturelles (le long des clés étrangères, comme n'importe qui a le réflexe de faire) sauf à coder pour une application précise.
À propos des jointures que l'on évite : c'est encore plus intéressant avec les clés naturelles puisqu'on a souvent là deux ou trois colonnes par index sinon plus, ce qui fait autant que l'on n'a pas à écrire en en oubliant. (Une des raisons pour lesquelles je préfère les clés arbitraires.)
J'ajoute aussi :
Il y a un domaine où on dénormalise à fond délibérément : les systèmes décisionnels (datawarehouse). Ce sont des systèmes séparés alimentés par les diverses applications d'une entreprise. Les perfs à la lecture passent devant les soucis de volumétrie ou de temps de mise à jour. Mais ladite mise à jour se fait en batch nocturne ou ouikénal.
On utilise rarement du code applicatif classique mais des outils spécialisés (ETL) qui se chargent de malaxer les données depuis plusieurs applications, calculer un milliard d'indicateurs, etc. Et avoir des vues déjà toute prêtes du côté de l'application dont on pompe les données est effectivement une bénédiction pour le développeur qui n'a pas à recoder les jointures dans son outil (surtout si lesdites jointures sont subtiles...).
Ces systèmes décisionnels (et les autres systèmes qui ont besoin de regarder « sous le capot » au niveau SQL) sont une des raisons qui doivent décourager de mettre de la logique (contraintes, cohérence statique, pas les flux et process) ailleurs que dans la base. À l'inverse, il existe des plugins (coûteux) pour les ETL courant pour lire par exemple dans SAP, l'archétype de l'application qui interdit que quiconque lise dans la base sans passer par lui (et ça donne ça :http://www.courtois.cc/blogeclectiq...)
Par contre, le code applicatif dans la base c'est pas glorieux pour l'indépendance envers les fournisseurs de BdD, il faut savoir ce qui est important pour son application, et coder au PPCD si on tient à avoir des données « libres » - d'où des compromis dans les fonctionnalités utilisables.
Merci :-)
For an english translation of these interesting comments, just use Google translate services.
Sorry, I didn’t even see I was replying in another language :-))))