On m'a demandé de créer quelque chose qui suit le coût quotidien à percevoir sur les comptes, et j'essaie de trouver un schéma de table de base de données qui prendrait en charge cela.
Voici ce que je sais
- La société compte plus de 2,5 millions de comptes
- Parmi ceux-ci, ils travaillent actuellement en moyenne 200 000 par mois (cela change avec les niveaux de dotation, qui sont actuellement faibles)
- Ils ont 13 types de coûts différents qu'ils aimeraient suivre, et ils ont averti qu'ils pourraient en ajouter d'autres à l'avenir
- Ils veulent que les coûts soient suivis quotidiennement
- Les coûts ne sont pas répartis sur l'ensemble de l'inventaire. Ils sont répartis sur le nombre de comptes travaillés par mois (200 000), ou les utilisateurs peuvent saisir des identifiants de compte pour appliquer un coût à un groupe de comptes, ou ils peuvent simplement spécifier à quels comptes appliquer le coût.
Ma première pensée a été une base de données normalisée:
Identifiant de compte Date CostTypeId Montant
Mon problème avec ceci est, faites le calcul. Ce tableau va devenir énorme rapidement. En supposant que les 13 types de coûts soient appliqués à tous les comptes actifs pour le mois en cours, c'est-à 200k * 13 * N days in month
-dire environ 75 à 80 millions d'enregistrements par mois, soit près d'un milliard d'enregistrements par an.
Ma deuxième pensée a été de le dénormaliser un peu
Identifiant de compte Date Coût total CostType1 CostType2 CostType3 CostType4 CostType5 CostType6 CostType7 CostType8 CostType9 CostType10 CostType11 CostType12 CostType13
Cette méthode est plus dénormalisée et peut créer jusqu'à 6 millions d'enregistrements par mois ( 200k * N days in month
), soit environ 72 millions par an. C'est beaucoup moins que la première méthode, mais si l'entreprise décide d'un nouveau type de coût à l'avenir, une autre colonne de base de données devra être ajoutée.
Des deux méthodes, laquelle préférez-vous? Pourquoi? Y a-t-il une autre alternative à laquelle vous pourriez penser qui gérerait mieux cela?
Je suis plus intéressé par les rapports de performance, à la fois les rapports résumés et détaillés. Le travail qui répartira les coûts sur les comptes sera exécuté tous les soirs lorsque personne n'est présent. Une préoccupation secondaire est la taille de la base de données. La base de données existante fait déjà près de 300 Go, et je pense que l'espace sur le disque est d'environ 500 Go.
La base de données est SQL Server 2005
Réponses:
Un milliard d'enregistrements par an, ce n'est pas beaucoup.
Avec le partitionnement (par type de coût peut-être) et l'archivage, il est gérable.
Le nombre d'éléments de données à stocker est toujours de 200k * 13 * N. En tant que colonnes, vous obtiendrez moins de lignes par page et cela prendra plus d'espace qu'en tant que lignes. Vous pouvez gagner si "CostType1" n'est pas un type de données de longueur fixe, mais il est marginal.
"KISS" comme on dit
la source
Bien que votre conception puisse certainement faire une différence de jour comme de nuit, dans ce cas, je me concentrerais davantage sur les index, y compris en couvrant les index si nécessaire. J'examinerais également certains des outils que SQL Server vous offre pour gérer les très grandes tables, telles que le partitionnement de table.
Pensez-y de cette façon, même s'il y a 80 milliards d'enregistrements dans le tableau, avec une indexation appropriée, ceux qui vous intéressent réellement à un moment donné seront regroupés physiquement sur le disque. En raison de la façon dont les données sont organisées dans SQL Server, les données divisées par limites d'index peuvent également se trouver dans une autre table car elles n'ont pas à lire la table entière pour obtenir ce dont elles ont besoin.
Si vous choisissez également de partitionner la table, vous pouvez améliorer le temps d'accès et l'insertion du temps.
la source
Je normaliserais. Nous avons fait une comptabilité analytique pour la rentabilité des comptes clients dans une banque et nous avons généré plus de 250 millions de lignes de coûts individuels en utilisant des centaines de pilotes qui ont été répartis par centre de coûts ou par grand livre ou par diverses autres techniques sur des millions de comptes chaque mois.
Par exemple, le coût total de l'entretien des distributeurs automatiques de billets a été réparti entre les comptes qui avaient utilisé des distributeurs automatiques de billets en fonction de la quantité relative d'utilisation. Donc, si 1 million de dollars a été dépensé pour l'entretien des guichets automatiques et que 5 clients l'ont utilisé une fois chacun et qu'un client l'a utilisé 5 fois, alors un client a coûté 0,5 million de dollars à la banque et les autres clients à la banque 0,1 million de dollars chacun. D'autres pilotes pourraient être beaucoup plus complexes.
En fin de compte, vous trouverez probablement que c'est rare - certains comptes ne reçoivent pas de coûts de certaines sources / pilotes - et certains comptes ne reçoivent rien. Dans un modèle normalisé, ces lignes n'existent pas. Dans le modèle dénormalisé, la ligne existe, avec quelques colonnes vides. En outre, dans un modèle normalisé clairsemé, vous devriez voir les performances s'améliorer, car l'existence d'une ligne est généralement plus rapide à vérifier (avec un index de couverture sur CostType) que la vérification de toutes les lignes avec non NULL dans un "compartiment" particulier (même avec index sur chaque colonne de montant - que vous pouvez voir commence à devenir très inutile).
la source
Indépendamment de l'avantage de performance, je serais certainement en faveur de l'option 1. L'option 2 serait de voler Peter pour payer Paul, à mon avis.
la source
J'irais avec l'option 1, puis si la vitesse de génération de rapports devenait un problème sur la route, j'ajouterais également le tableau 2 et le remplirais dans une base de données de génération de rapports dans une sorte de processus automatisé de nuit / hors-pointe.
Vous pouvez également envisager de regrouper la structure quotidienne du tableau 2 en d'autres cumuls hebdomadaires, mensuels, trimestriels et annuels si cela est justifié.
Mais, comme je l'ai dit, je choisirais également de stocker les données «brutes» sous une forme appropriée (normalisée).
la source
Compte tenu des volumes que vous mentionnez, je choisirais la deuxième option, mais sans TotalCost. On pourrait dire que c'est encore normalisé.
Modifier: comme alternative, et en fonction de vos besoins et de la taille du AccountId, vous pouvez également envisager les éléments suivants:
Avec cette conception, vous pouvez toujours ajouter un TotalCost dénormalisé à la première table et le faire recalculer tous les soirs, ce qui permet d'exécuter certains rapports uniquement sur la première table.
la source
TotalCost
là parce que la majorité des rapports sont résumés, et j'ai pensé qu'il serait plus rapide d'interroger une seule valeur que d'ajouter 13 valeurs différentes.vous devez en fait diviser la première table en deux tables afin de pouvoir utiliser une sous-requête et sélectionner la deuxième ligne comme colonne ou plusieurs colonnes. il est plus flexible de cette façon et par là, vous pouvez obtenir un résultat comme le second plus facilement.
la source