2009-05-28 2 views
1

Je suis curieux de savoir quelle est la meilleure façon de modéliser cela pour des performances optimisées ... pas aussi préoccupé par le réel le temps de l'intégrité des donnéesManière efficace de modéliser les données agrégées d'une relation plusieurs-à-un (par exemple, les votes comptent sur une question stackoverflow)

Je vais continuer avec l'exemple stackoverflow

Question 
    id 
    title 
Votes 
    id 
    user 
    question 

Une question a beaucoup de votes

cependant, nous sommes seulement préoccupés par de nombreuses requêtes avec le nombre total de voix (par exemple montrer à côté de la question).

Une bonne théorie db relationnelle créerait les deux entités (Q et V) comme des relations séparées, nécessitant une jointure puis une somme ou un appel global.

Une autre possibilité consiste à rompre la forme normale et à matérialiser occasionnellement la valeur agrégée des votes en tant qu'attribut dans Question (par exemple, questions-réponses). Cependant, en fonction de la façon dont vous êtes prêt à laisser vos données de vote, vous avez besoin de beaucoup plus de droits sur cet enregistrement de Question ... ce qui entrave les performances.

D'autres techniques impliquant la mise en cache, etc. peuvent être utilisées. Mais je me demandais juste, la performance sage quelle est la meilleure solution? Disons que le site a un trafic plus élevé et reçoit beaucoup plus de votes que de questions.

Ouvert aux modèles non relationnels.

Répondre

1

Il est peu probable qu'une jointure soit trop lente dans ce cas, surtout si vous avez un index sur (question) dans le tableau Votes.

Si elle est vraiment trop lent, vous pouvez mettre en cache le décompte des voix dans la table Question:

id - title - votecount 

Vous pouvez mettre à jour le votecount chaque fois que vous enregistrez un vote. Par exemple, à partir d'une procédure stockée ou directement à partir du code de votre application.

Ces mises à jour sont difficiles, mais puisque vous n'êtes pas si inquiet à propos de la cohérence, je suppose que c'est correct si le vote n'est pas toujours tout à fait correct. Pour corriger les erreurs, vous pouvez périodiquement régénérer tous les comptes cachés comme:

UPDATE q 
SET votecount = count(v.question) 
FROM questions q 
LEFT JOIN votes v on v.question = q.id 

Le nombre total (de v.question) renvoie 0 si aucune question n'a été trouvée, par opposition à compter (*), qui renvoie 1.

Si les verrous sont un problème, pensez à utiliser « avec (nolock) » ou « niveau d'isolation des transactions mis en lecture UNCOMMITED » aux serrures de dérivation (à nouveau, basé sur l'intégrité des données étant une priorité faible.)

Comme alternative Pour nolock, considérez "read committed snapshot", qui est destiné aux bases de données avec une activité de lecture importante et moins d'écriture. Vous pouvez l'activer avec:

ALTER DATABASE YourDb SET READ_COMMITTED_SNAPSHOT ON; 

Il est disponible pour SQL Server 2005 et versions ultérieures. C'est ainsi qu'Oracle fonctionne par défaut, et c'est ce que stackoverflow lui-même utilise. Il y a même un coding horror blog entry à ce sujet.

+0

droite. J'ai abordé la matérialisation du nombre de votes suggéré dans la question. Je me demandais s'il y a un autre moyen car cela provoque le double des écritures (verrouiller toutes les lectures) Je sais avec une indexation correcte ça devrait aller. mais si je récupère beaucoup de questions et peut-être que j'ai plusieurs plusieurs à plusieurs relations (par exemple votes et nombre de commentaires), les jointures deviennent méchantes – nategood

+0

Post édité. Veillez à ne pas effectuer d'optimisation prématurée. il doit y avoir une preuve solide, soutenue par des chiffres, de problèmes de performance avant que je ne m'éloigne de la jointure normale. – Andomar

1

J'ai utilisé des vues indexées de sql 2005 partout pour ce genre de chose sur un site de réseautage social. Notre charge était certainement un ratio élevé de lectures/écritures, donc cela a bien fonctionné pour nous.

+0

Je suis d'accord avec hainstech. Créez une vue indexée de la table Votes et regroupez-la par question et compte. – Jeff

0

Je suggère de garder le vote en mémoire pour la durée de vie de l'application. Pourquoi frapper un db pour quelque chose d'aussi simple que le comptage, quand à un moment donné vous aurez chargé l'article une fois et demandé quel était le montant initial sur demande. Il a aussi beaucoup à voir avec la façon dont vous implémentez des dépôts, si votre objet question paresseux charge les votes, mais souhaite charger le nombre de votes, vous pouvez accélérer le processus sans avoir à le garder en mémoire. Toujours garder les votes en db, il suffit de maintenir le nombre dans votre application

Questions connexes