Dénormaliser pour améliorer les performances? Cela semble convaincant, mais il ne tient pas la route.
Chris Date, qui en compagnie du Dr Ted Codd était le promoteur initial du modèle de données relationnelles, a manqué de patience avec des arguments mal informés contre la normalisation et les a systématiquement démolis en utilisant une méthode scientifique: il a obtenu de grandes bases de données et testé ces assertions.
Je pense qu'il l'a écrit dans Relational Database Writings 1988-1991, mais ce livre a ensuite été intégré à la sixième édition d' Introduction to Database Systems , qui est le texte définitif sur la théorie et la conception des bases de données, dans sa huitième édition au moment où j'écris et qui restera probablement en version imprimée pour les décennies à venir. Chris Date était un expert dans ce domaine lorsque la plupart d'entre nous couraient encore pieds nus.
Il a constaté que:
- Certains d'entre eux tiennent pour des cas spéciaux
- Tous ne sont pas rentables pour une utilisation générale
- Tous sont nettement pires pour d'autres cas spéciaux
Tout revient à atténuer la taille de l'ensemble de travail. Les jointures impliquant des clés correctement sélectionnées avec des index correctement configurés sont bon marché, pas chers, car elles permettent un élagage significatif du résultat avant la matérialisation des lignes.
La matérialisation du résultat implique des lectures de disques en vrac qui sont l'aspect le plus coûteux de l'exercice par ordre de grandeur. La réalisation d'une jointure, en revanche, nécessite logiquement la récupération des seules clés . En pratique, même les valeurs de clé ne sont pas récupérées: les valeurs de hachage de clé sont utilisées pour les comparaisons de jointures, ce qui réduit le coût des jointures à plusieurs colonnes et réduit radicalement le coût des jointures impliquant des comparaisons de chaînes. Non seulement sa place dans le cache sera beaucoup plus importante, mais il y aura beaucoup moins de lecture de disque à faire.
De plus, un bon optimiseur choisira la condition la plus restrictive et l'appliquera avant d'effectuer une jointure, en tirant très efficacement parti de la haute sélectivité des jointures sur les index à cardinalité élevée.
Certes, ce type d'optimisation peut également être appliqué aux bases de données dénormalisées, mais le type de personnes qui souhaitent dénormaliser un schéma ne pense généralement pas à la cardinalité quand (si) elles configurent des index.
Il est important de comprendre que les analyses de table (examen de chaque ligne d'une table au cours de la production d'une jointure) sont rares dans la pratique. Un optimiseur de requête choisira une analyse de table uniquement lorsqu'un ou plusieurs des éléments suivants sont conservés.
- Il y a moins de 200 lignes dans la relation (dans ce cas, un scan sera moins cher)
- Il n'y a pas d'index appropriés sur les colonnes de jointure (s'il est utile de se joindre à ces colonnes, alors pourquoi ne sont-elles pas indexées? Corrigez-le)
- Une contrainte de type est requise avant que les colonnes puissent être comparées (WTF?! Corrigez-le ou rentrez chez vous) VOIR LES NOTES FINALES POUR LE NUMÉRO ADO.NET
- L'un des arguments de la comparaison est une expression (pas d'index)
L'exécution d'une opération est plus coûteuse que son absence. Cependant, effectuer la mauvaise opération, être forcé dans des E / S disque inutiles, puis éliminer les scories avant d'effectuer la jointure dont vous avez vraiment besoin, est beaucoup plus coûteux. Même lorsque la «mauvaise» opération est précalculée et que les index ont été judicieusement appliqués, il reste une pénalité importante. Dénormaliser pour précalculer une jointure - nonobstant les anomalies de mise à jour impliquées - est un engagement envers une jointure particulière. Si vous avez besoin d' une autre jointure, cet engagement va vous coûter gros .
Si quelqu'un veut me rappeler que le monde est en mutation, je pense que vous constaterez que des ensembles de données plus volumineux sur un matériel plus grognon exagèrent simplement la propagation des résultats de Date.
Pour tous ceux qui travaillent sur des systèmes de facturation ou des générateurs de courrier indésirable (honte à vous) et mettent la main au clavier avec indignation pour me dire que vous savez pertinemment que la dénormalisation est plus rapide, désolé mais vous vivez dans l'un des spéciaux cas - en particulier, le cas où vous traitez toutes les données, dans l'ordre. Ce n'est pas un cas général, et vous êtes justifié dans votre stratégie.
Vous n'êtes pas justifié de le généraliser à tort. Voir la fin de la section des notes pour plus d'informations sur l'utilisation appropriée de la dénormalisation dans les scénarios d'entreposage de données.
Je voudrais également répondre à
Les joints sont juste des produits cartésiens avec du brillant à lèvres
Quelle charge de conneries. Les restrictions sont appliquées le plus tôt possible, la plus restrictive en premier. Vous avez lu la théorie, mais vous ne l'avez pas comprise. Les jointures sont traitées comme des "produits cartésiens auxquels s'appliquent les prédicats" uniquement par l'optimiseur de requêtes. Il s'agit d'une représentation symbolique (une normalisation, en fait) pour faciliter la décomposition symbolique afin que l'optimiseur puisse produire toutes les transformations équivalentes et les classer par coût et sélectivité afin de pouvoir sélectionner le meilleur plan de requête.
La seule façon d'obtenir l'optimiseur pour produire un produit cartésien est de ne pas fournir un prédicat: SELECT * FROM A,B
Remarques
David Aldridge fournit quelques informations supplémentaires importantes.
Il existe en effet une variété d'autres stratégies en plus des index et des analyses de table, et un optimiseur moderne les coûtera toutes avant de produire un plan d'exécution.
Un conseil pratique: s'il peut être utilisé comme clé étrangère, indexez-le, de sorte qu'une stratégie d'indexation soit disponible pour l'optimiseur.
J'étais plus intelligent que l'optimiseur MSSQL. Cela a changé il y a deux versions. Maintenant, cela m'apprend généralement . Il s'agit, dans un sens très réel, d'un système expert, codifiant toute la sagesse de nombreuses personnes très intelligentes dans un domaine suffisamment fermé pour qu'un système fondé sur des règles soit efficace.
"Bollocks" peut avoir été sans tact. On me demande d'être moins hautain et de me rappeler que les mathématiques ne mentent pas. C'est vrai, mais toutes les implications des modèles mathématiques ne doivent pas nécessairement être prises à la lettre. Les racines carrées des nombres négatifs sont très pratiques si vous évitez soigneusement d'examiner leur absurdité (jeu de mots là-bas) et assurez-vous de les annuler toutes avant d'essayer d'interpréter votre équation.
La raison pour laquelle j'ai répondu si sauvagement est que la déclaration telle qu'elle est libellée dit que
Les jointures sont des produits cartésiens ...
Cela peut ne pas être ce que voulait dire , mais il est ce qui a été écrit, et il est absolument faux. Un produit cartésien est une relation. Une jointure est une fonction. Plus précisément, une jointure est une fonction à valeur relationnelle. Avec un prédicat vide, il produira un produit cartésien et vérifier qu'il le fait est une vérification d'exactitude pour un moteur de requête de base de données, mais personne n'écrit des jointures sans contrainte dans la pratique parce qu'elles n'ont aucune valeur pratique en dehors d'une salle de classe.
J'ai appelé cela parce que je ne veux pas que les lecteurs tombent dans le piège ancien de confondre le modèle avec la chose modélisée. Un modèle est une approximation, délibérément simplifiée pour une manipulation pratique.
La coupure pour la sélection d'une stratégie de jointure de table-scan peut varier selon les moteurs de base de données. Elle est affectée par un certain nombre de décisions d'implémentation telles que le facteur de remplissage du nœud d'arbre, la taille de la valeur-clé et les subtilités de l'algorithme, mais d'une manière générale, l'indexation hautes performances a un temps d'exécution de k log n + c . Le terme C est une surcharge fixe principalement constituée de temps de configuration, et la forme de la courbe signifie que vous n'obtenez pas de gain (par rapport à une recherche linéaire) tant que n n'est pas dans les centaines.
Parfois, la dénormalisation est une bonne idée
La dénormalisation est un engagement envers une stratégie de jointure particulière. Comme mentionné précédemment, cela interfère avec d' autres stratégies de jointure. Mais si vous avez des compartiments d'espace disque, des modèles d'accès prévisibles et une tendance à en traiter une grande partie ou la totalité, le précalcul d'une jointure peut être très utile.
Vous pouvez également déterminer les chemins d'accès que votre opération utilise généralement et précalculer toutes les jointures pour ces chemins d'accès. C'est la prémisse derrière les entrepôts de données, ou du moins c'est quand ils sont construits par des gens qui savent pourquoi ils font ce qu'ils font, et pas seulement pour la conformité aux mots à la mode.
Un entrepôt de données correctement conçu est produit périodiquement par une transformation en masse à partir d'un système de traitement des transactions normalisé. Cette séparation des bases de données des opérations et des rapports a pour effet très souhaitable d'éliminer le conflit entre OLTP et OLAP (traitement des transactions en ligne, c'est-à-dire saisie des données, et traitement analytique en ligne, c'est-à-dire rapports).
Un point important ici est qu'en dehors des mises à jour périodiques, l'entrepôt de données est en lecture seule . Cela rend sans objet la question des anomalies de mise à jour.
Ne commettez pas l'erreur de dénormaliser votre base de données OLTP (la base de données sur laquelle s'effectue la saisie des données). Cela peut être plus rapide pour les cycles de facturation, mais si vous le faites, vous obtiendrez des anomalies de mise à jour. Avez-vous déjà essayé d'obtenir que Reader's Digest arrête de vous envoyer des trucs?
L'espace disque est bon marché de nos jours, alors assommez-vous. Mais la dénormalisation n'est qu'une partie de l'histoire des entrepôts de données. Des gains de performances beaucoup plus importants sont dérivés des valeurs cumulées précalculées: les totaux mensuels, ce genre de choses. Il s'agit toujours de réduire l'ensemble de travail.
Problème ADO.NET avec des incompatibilités de types
Supposons que vous ayez une table SQL Server contenant une colonne indexée de type varchar et que vous utilisez AddWithValue pour passer un paramètre contraignant une requête sur cette colonne. Les chaînes C # sont Unicode, donc le type de paramètre déduit sera NVARCHAR, qui ne correspond pas à VARCHAR.
VARCHAR vers NVARCHAR est une conversion qui s'élargit donc cela se produit implicitement - mais dites adieu à l'indexation et bonne chance pour comprendre pourquoi.
"Comptez les hits du disque" (Rick James)
Si tout est mis en cache en RAM, ils JOINs
sont plutôt bon marché. C'est-à-dire que la normalisation n'a pas beaucoup de pénalité de performance .
Si un schéma "normalisé" fait JOINs
beaucoup frapper le disque, mais que le schéma équivalent "dénormalisé" n'aurait pas à frapper le disque, la dénormalisation remporte un concours de performances.
Commentaire de l'auteur original: Les moteurs de base de données modernes sont très bons pour organiser le séquencement des accès afin de minimiser les erreurs de cache pendant les opérations de jointure. Ce qui précède, bien que vrai, pourrait être mal interprété comme impliquant que les jointures sont nécessairement problématiques sur des données volumineuses. Cela entraînerait une mauvaise prise de décision de la part des développeurs inexpérimentés.