Gains de performance vs Normalisation de vos tables?

Ok, je sais que vous allez probablement tous me tuer pour avoir posé cette question, mais je suis entré dans une discussion avec un collègue sur l'une de nos tables de database et il m'a posé une question dont je connais la réponse mais je ne pouvais pas expliquez que c'est la meilleure façon.

Je vais simplifier la situation pour la simplicité de la question, nous avons une assez grande table de personnes / users. Maintenant, parmi d'autres données stockées, datatables en question sont les suivantes: nous avons un simNumber, cellNumber et l'adresse IP de cette simulation.

Maintenant, je dis que nous devrions faire une table appelons-le SimTable et mettre ces 3 inputs dans la table sim, puis mettre un FK dans le UsersTable reliant les deux. Pourquoi? Parce que c'est ce qui m'a toujours été enseigné NORMALISEZ vos tables !!! Ok donc tout va bien à cet égard.

Mais maintenant, mon ami me dit oui, mais maintenant, quand vous voulez interroger un numéro de téléphone d'users, SQL doit maintenant aller et:

  1. searchr l'user
  2. searchr le sim fk
  3. searchr la ligne SIM correcte dans la database SIM
  4. get le numéro de téléphone

Maintenant, quand je vais et request 10000 numéros de téléphone d'users, le nombre d'opérations effectuées sérieusement augmente en taille.

Vs l'autre approche

  1. searchr l'user
  2. find le numéro de téléphone

Maintenant, l'argument est purement basé sur la performance. Autant que je comprenne pourquoi nous normalisons datatables (pour supprimer datatables redondantes, la maintenabilité, apporter des modifications aux données dans une table qui se propagent, etc.) Il me semble que l'approche avec datatables dans une table sera plus rapide ou au less less de tâches / opérations pour me donner datatables que je veux?

Alors, quel est le cas dans cette situation? J'espère que je n'ai rien demandé de follement bête, il est tôt le matin alors pardonnez-moi si je ne pense pas clairement

La technologie impliquée dans MS SQL Server 2012

[EDIT] Cet article ci-dessous aborde aussi quelques concepts que j'ai mentionnés plus haut http://databases.about.com/od/specificproducts/a/Should-I-Normalize-My-Database.htm

Le but de la normalisation n'est pas la performance. L'objective est de modéliser correctement vos données avec une redondance minimale afin d'éviter les anomalies de données.

Supposons par exemple que deux users partagent le même téléphone. Si vous stockez les téléphones dans la table des users, vous auriez un numéro de sim, une adresse IP et un numéro de cellule stockés sur la rangée de chaque user.

Ensuite, vous changez l'adresse IP sur une ligne mais pas sur l'autre. Comment un numéro de sim peut-il avoir deux adresses IP? Est-ce que c'est même valable? Laquelle est correcte? Comment corrigeriez-vous de telles divergences? Comment pourriez-vous les détecter?

Il y a des moments où la dénormalisation vaut la peine, si vous avez vraiment besoin d'optimiser l'access aux données pour une requête que vous exécutez très fréquemment. Mais la dénormalisation a un coût, alors soyez prêt à vous engager dans un travail beaucoup plus manuel pour prendre la responsabilité de l'intégrité des données. Plus de code, plus de tests, plus de tâches de nettoyage. Est-ce que cela count quand on considère la «performance» du projet dans son set?


Re commentaires:

Je suis d'accord avec @JoelBrown, dès que vous implémentez votre premier cas de dénormalisation, vous compromettez l'intégrité des données.

Je vais développer ce que Joel mentionne comme "réfléchi". La dénormalisation profite à des requêtes spécifiques . Vous devez donc connaître les requêtes que vous avez dans votre application et celles que vous devez optimiser. Faites cela de façon conservasortingce, car si la dénormalisation peut aider une requête spécifique, elle nuit aux performances pour toutes les autres utilisations des mêmes données. Vous devez donc savoir si vous devez interroger datatables de différentes manières.

Exemple: supposons que vous concevez une database pour StackOverflow et que vous souhaitiez prendre en charge les tags pour les questions. Chaque question peut avoir un certain nombre d'labels, et chaque label peut s'appliquer à beaucoup de questions. La manière normalisée de concevoir ceci est de créer une troisième table, en appariant des questions avec des labels. C'est le model de données physique pour une relation plusieurs-à-plusieurs:

Questions ----<- QuestionsTagged ->---- Tags 

Mais vous ne voulez pas faire la jointure pour get des balises pour une question donnée, alors vous placez les balises dans une string séparée par des virgules dans la table des questions. Cela rend plus rapide l'interrogation d'une question donnée et de ses balises associées.

Mais que se passe-t-il si vous souhaitez également searchr une balise spécifique et find ses questions connexes? Si vous utilisez la design normalisée, il s'agit simplement d'une requête sur la table plusieurs-à-plusieurs, mais sur la colonne de l' tag .

Mais si vous dénormaliser en stockant des balises sous la forme d'une list séparée par des virgules dans la table Questions, vous devrez searchr des balises en tant que sous-strings dans cette list séparée par des virgules. La search de sous-strings ne peut pas être indexée avec un index de style B-tree standard, et donc la search de questions connexes devient une parsing de table coûteuse. Il est également plus complexe et inefficace d'insert et de supprimer une balise, ou d'appliquer des contraintes telles que l'unicité ou les foreign keys.

C'est ce que je veux dire par dénormalisation faisant une amélioration pour un type de requête au désortingment d'autres utilisations des données . C'est pourquoi c'est une bonne idée de commencer avec tout dans la forme normale, puis de refactoriser les designs dénormalisées plus tard au cas par cas que vos goulots d'étranglement se révèlent.

Cela remonte à la vieille sagesse:

"L'optimization prématurée est la racine de tous les maux" – Donald Knuth

En d'autres termes, ne dénormalisez pas avant de pouvoir démontrer pendant le test de charge (a) que cela améliore réellement les performances justifiant la perte d'intégrité des données et (b) ne dégrade pas les performances des autres cas de manière inacceptable.

Il semble que vous compreniez déjà les avantages de la normalisation, alors je ne vais pas les couvrir.

Il y a quelques considérations ici: 1. Un user a-t-il toujours un seul et unique numéro de téléphone? Si c'est le cas, il est toujours normal de les append à la table des users. Toutefois, si l'user ne peut pas avoir de numéro de téléphone ou plusieurs numéros de téléphone, les détails du téléphone doivent être conservés dans un tableau séparé.

  1. En supposant que vous les avez dans des arrays séparés, mais après avoir effectué des tests de performance, vous avez constaté que la participation à ces deux tables avait un effet significatif sur les performances, vous pouvez alors délibérément dénormaliser les tables pour des gains de performance.

D'autres ont déjà fourni quelques bons points et vous pouvez également vouloir jeter un coup d'oeil à ceci .

Je voudrais juste mentionner un autre aspect qui est souvent négligé: I / O tend à être la plus grande composante du coût de la plupart des requêtes, et la dénormalisation augmente généralement la taille de stockage des données, rendant ainsi le cache de SGBD "plus petit".

Si votre database normalisée entre dans le cache et ne l'est pas, vous risquez d'observer une diminution des performances pour cette dernière.

Et vous ne serez pas en mesure de repérer cela en développement, sauf si vous avez réellement la quantité de données qui est similaire à la production. C'est l'une des nombreuses raisons pour lesquelles vous ne devriez jamais, jamais dénormaliser sans mesures solides (sur des quantités représentatives de données) pour le justifier.