Normalisation

La structure logique de la base de données, comprenant les tables et les relations qui les unissent, constitue le cœur d'une base de données relationnelle optimisée. Si elle est bien pensée, les performances de la base de données et de l'application seront optimales. À l'inverse, une mauvaise structure logique peut détériorer les performances de tout le système.

La normalisation de la structure logique d'une base de données implique l'emploi de méthodes formelles pour répartir les données sur plusieurs tables connexes. Une base de données normalisée se caractérise par un plusieurs tables étroites comportant un nombre réduit de colonnes. À l'inverse, une base de données non normalisée comporte un grand nombre de tables larges avec plus de colonnes.

Si elle est raisonnable, la normalisation apporte souvent une amélioration des performances. Quand des index utiles sont disponibles, l'optimiseur de requête SQL Server peut très facilement sélectionner des jointures rapides et efficaces entre les tables.

Les avantages de la normalisation sont notamment les suivants :

  • une plus grande rapidité des tris et des créations d'index ;

  • un plus grand nombre d'index cluster. Pour plus d'informations, consultez Indications pour la conception d'index cluster.

  • des index plus étroits et plus compacts ;

  • un nombre moindre d'index par table, qui améliore les performances des instructions SELECT, INSERT, UPDATE et DELETE ;

  • moins de valeurs NULL et moins de risques d'incohérences, permettant d'obtenir une base de données plus compacte.

Lorsque la normalisation augmente, le nombre et la complexité des jointures nécessaires pour récupérer les données augmentent aussi. Or, des jointures relationnelles trop complexes entre des tables trop nombreuses peuvent avoir un effet néfaste sur les performances. Un niveau raisonnable de normalisation se traduit souvent par peu de requêtes exécutées à intervalles réguliers qui utilisent des jointures faisant intervenir plus de quatre tables.

Il arrive parfois que la structure logique de la base de données soit déjà figée, auquel cas il est irréaliste de la remodeler entièrement. Toutefois, même dans ce cas, il est parfois possible de normaliser sélectivement une table de grande taille, en la fractionnant en plusieurs tables plus petites. Si l'accès à la base de données est effectué par le biais de procédures stockées, cette modification du schéma pourra être effectuée sans incidence sur les applications. Sinon, il est parfois possible de créer une vue cachant la modification du schéma aux applications.

Obtenir une base de données bien conçue

Dans la théorie de conception des bases de données relationnelles, des règles de normalisation identifient les attributs qui doivent être présents (ou absents) dans une base de données bien conçue. Une discussion approfondie concernant la normalisation dépasse l'objectif de cette rubrique. Néanmoins, il existe quelques règles qui peuvent vous aider à réaliser une base de données bien conçue :

  • Une table doit avoir un identificateur.

    La théorie de la conception des bases de données pose comme loi fondamentale que chaque table doit avoir un identificateur de ligne unique, une colonne ou un jeu de colonnes servant à distinguer un enregistrement d'une table de tous les autres. Chaque table doit avoir une colonne d'identification ; par ailleurs, deux enregistrements ne peuvent pas partager le même identificateur. La ou les colonnes faisant office d'identificateur de ligne unique pour une table constituent la clé primaire de cette table. Dans la base de données AdventureWorks2008R2, chaque table contient une colonne d'identité comme colonne de clé primaire. Par exemple, VendorID est la clé primaire de la table Purchasing.Vendor.

  • Une table ne doit stocker que les données d'un type d'entité unique.

    En essayant de stocker trop d'informations dans une table, vous risquez de nuire à l'efficacité et la fiabilité de la gestion des données de cette table. Dans l'exemple de base de données AdventureWorks2008R2, les informations sur les commandes et les clients sont stockées dans des tables distinctes. Bien qu'il soit possible de disposer de colonnes contenant des informations pour la commande et le client dans une même table, une telle structure n'est pas sans poser quelques problèmes. Les informations sur le client, à savoir le nom et l'adresse, doivent être ajoutées et stockées de manière redondante pour chaque commande. La base de données exige un espace de stockage supplémentaire. Si l'adresse d'un client vient à changer, la modification devra être effectuée pour chaque commande. Et si la dernière commande d'un client est supprimée de la table Sales.SalesOrderHeader, les informations concernant ce client sont perdues.

  • Il faut éviter dans les tables des colonnes acceptant des valeurs NULL.

    Les tables peuvent comporter des colonnes définies comme tolérant les valeurs NULL. Une valeur NULL indique qu'il n'y a pas de valeur. Même s'il peut être utile d'autoriser les valeurs NULL dans certains cas isolés, vous devez les utiliser avec parcimonie. En effet, elles exigent un traitement particulier qui accroît la complexité des opérations sur les données. Dans le cas d'une table constituée de plusieurs colonnes autorisant les valeurs NULL et où plusieurs lignes présentent de telles valeurs, nous vous recommandons de placer ces colonnes dans une autre table liée à la table primaire. Lorsque les données sont stockées dans deux tables distinctes, la table primaire conserve une structure simple, tout en étant capable à l'occasion de stocker ces informations.

  • Une table ne doit pas comporter de valeurs ni de colonnes répétitives.

    La table relative à un élément de la base de données ne doit pas contenir une liste de valeurs pour une information spécifique. Par exemple, un produit de la base de données AdventureWorks2008R2 peut être acheté auprès de plusieurs fournisseurs. S'il existe une colonne dans la table Production.Product pour le nom du fournisseur, ceci pose un problème. Une solution consiste à stocker le nom de tous les fournisseurs dans la colonne. Toutefois, il devient alors difficile d'afficher une liste des fournisseurs individuels. Une autre solution consiste à modifier la structure de la table de façon à ajouter une colonne pour le nom du deuxième fournisseur. Toutefois, cette solution est limitée à deux fournisseurs. En outre, une autre colonne doit être ajoutée si un produit a trois fournisseurs.

    Si vous devez stocker une liste de valeurs dans une colonne unique, ou si vous avez plusieurs colonnes pour un même élément de données, telle que TelephoneNumber1, and TelephoneNumber2, envisagez de placer les données dupliquées dans une autre table, en créant un lien vers la table primaire. La base de données AdventureWorks2008R2 contient une table Production.Product pour les informations sur les produits, une table Purchasing.Vendor pour les informations sur les fournisseurs et une troisième table Purchasing.ProductVendor. Cette troisième table stocke uniquement les valeurs d'ID des produits et les ID des fournisseurs des produits. Une telle structure permet d'avoir plusieurs fournisseurs pour un même produit, sans qu'il soit nécessaire de modifier la définition des tables ; elle présente en outre l'avantage de ne pas allouer d'espace de stockage superflu aux produits qui n'ont qu'un seul fournisseur.