Stockage efficace d'ensembles de paires clé-valeur avec des clés très différentes


9

J'ai hérité d'une application qui associe différents types d'activités à un site. Il existe environ 100 types d'activités différents et chacun a un ensemble différent de 3 à 10 champs. Cependant, toutes les activités ont au moins un champ de date (peut être n'importe quelle combinaison de date, date de début, date de fin, date de début planifiée, etc.) et un champ de personne responsable. Tous les autres champs varient considérablement et un champ de date de début ne sera pas nécessairement appelé "Date de début".

La création d'une table de sous-types pour chaque type d'activité entraînerait un schéma avec 100 tables de sous-types différentes, ce qui serait trop difficile à gérer. La solution actuelle à ce problème consiste à stocker les valeurs d'activité sous forme de paires clé-valeur. Il s'agit d'un schéma grandement simplifié du système actuel pour faire passer le message.

entrez la description de l'image ici

Chaque activité a plusieurs champs d'activité; chaque site a plusieurs activités et la table SiteActivityData stocke les KVP pour chaque siteActivity.

Cela rend l'application (basée sur le Web) très facile à coder car tout ce que vous avez vraiment à faire est de parcourir les enregistrements dans SiteActivityData pour une activité donnée et d'ajouter une étiquette et un contrôle d'entrée pour chaque ligne d'un formulaire. Mais il y a beaucoup de problèmes:

  • L'intégrité est mauvaise; il est possible de placer un champ dans SiteActivityData qui n'appartient pas au type d'activité, et DataValue est un champ varchar, donc les nombres et les dates doivent être constamment castés.
  • Le reporting et l'interrogation ad hoc de ces données sont difficiles, sujettes aux erreurs et lentes. Par exemple, obtenir une liste de toutes les activités d'un certain type qui ont une date de fin dans une plage spécifiée nécessite des pivots et la conversion de varchars en dates. Les rédacteurs du rapport détestent ce schéma, et je ne leur en veux pas.

Donc, ce que je recherche, c'est un moyen de stocker un grand nombre d'activités qui n'ont presque aucun champ en commun d'une manière qui facilite le reporting. Ce que j'ai trouvé jusqu'à présent, c'est d'utiliser XML pour stocker les données d'activité dans un format pseudo-noSQL:

entrez la description de l'image ici

La table d'activité contiendrait le XSD pour chaque activité, éliminant ainsi le besoin de la table ActivityField. SiteActivity contiendrait le XML de valeur-clé de sorte que chaque activité d'un site serait désormais sur une seule ligne.

Une activité ressemblerait à quelque chose comme ça (mais je ne l'ai pas complètement étoffée):

<SomeActivityType>
  <SomeDateField type="StartDate">2000-01-01</SomeDateField>
  <AnotherDateField type="EndDate">2011-01-01</AnotherDateField>
  <EmployeeId type="ResponsiblePerson">1234</EmployeeId>
  <SomeTextField>blah blah</SomeTextField>
  ...

Avantages:

  • Le XSD validerait le XML, détectant des erreurs comme la mise d'une chaîne dans un champ numérique au niveau de la base de données, ce qui était impossible avec l'ancien schéma qui stockait tout dans varchar.
  • Le jeu d'enregistrements de KVP utilisé pour créer les formulaires Web peut être facilement reproduit à l'aide de select ... from ActivityXML.nodes('/SomeActivityType/*') as T(r)
  • Une sous-requête xpath du XML peut être utilisée pour produire un jeu de résultats qui contient des colonnes pour la date de début, la date de fin, etc. sans utiliser de pivot, quelque chose comme select ActivityXML.value('.[@type=StartDate]', 'datetime') as StartDate, ActivityXML.value('.[@type=EndDate]', 'datetime') as EndDate from SiteActivity where...

Cela vous semble-t-il une bonne idée? Je ne peux pas penser à d'autres façons de stocker un si grand nombre d'ensembles de propriétés différents. Une autre pensée que j'avais était de conserver le schéma existant et de le traduire en quelque chose de plus facile à interroger dans un entrepôt de données, mais je n'ai jamais conçu de schéma en étoile auparavant et je n'aurais aucune idée par où commencer.

Question supplémentaire: si je définis une balise comme ayant un type de données de date dans le XSD xs:date, SQL Server va-t-il l'indexer en tant que valeur de date? Je suis inquiet si je recherche par date, il devra convertir la chaîne de date en une valeur de date et souffler toute chance d'utiliser un index.


Dans quelle mesure les données des rapports doivent-elles être à jour? Les rapports atteindront-ils la production?
James Anderson

La plupart des rapports atteignent maintenant un entrepôt de données (qui n'est pas vraiment un DW, c'est essentiellement une copie du schéma transactionnel de production avec un crapton de vues et de tables d'autres bases de données ajoutées). Avoir des rapports périmés est acceptable, mais ce serait un bonus si cela pouvait être en direct.
Paul Abbott

Quel est le chevauchement dans les champs? Est-ce que dix champs couvrent les 100 sous-types ou y a-t-il environ 500 champs entièrement distincts?
Jon of All Trades

Il y a 72 champs et 75 types d'activités. 30 champs ne sont utilisés que par une seule activité et la plupart des autres sont utilisés par 5 à 10 activités. Il y a une poignée de champs qui sont utilisés par environ 30 activités différentes. Pour la plupart, il n'y a pas beaucoup de points communs entre les activités.
Paul Abbott

Réponses:


7

Donc, ce que je recherche, c'est un moyen de stocker un grand nombre d'activités qui n'ont presque aucun champ en commun d'une manière qui facilite le reporting.

Pas assez de représentants pour commenter d'abord, alors c'est parti!

Si l'objectif principal est de créer des rapports et que vous avez un DW (même s'il ne s'agit pas d'un schéma en étoile), je vous recommande d'essayer de l'intégrer dans un schéma en étoile. Les avantages sont des requêtes simples et rapides. L'inconvénient est ETL, mais vous envisagez déjà de déplacer les données vers une nouvelle conception et ETL vers le schéma en étoile est probablement plus simple à construire et à maintenir qu'une solution de wrapper XML (et SSIS est inclus dans votre licence SQL Server). De plus, il démarre le processus d'une conception de rapports / d'analyse reconnue.

Alors, comment faire ... On dirait que vous avez ce qu'on appelle un fait sans fait . Il s'agit d'une intersection d'attributs qui définissent un événement sans mesure associée (comme un prix de vente). Vous avez des dates disponibles pour certaines ou toutes vos activités? Vous devriez probablement avoir une intersection entre une activité, un site et des dates.

DimActivity- Je suppose qu'il existe un modèle, quelque chose qui peut vous permettre de les décomposer en colonnes au moins relativement partagées. Si oui, vous pouvez en avoir trois? cinq? dimensions des classes d'activités. Au pire, vous avez quelques colonnes cohérentes, telles que le nom de l'activité, vous pouvez filtrer et vous laissez des en-têtes généraux tels que "Attribut1", etc. pour les détails aléatoires restants.

Vous n'avez pas besoin de tout dans la dimension - il ne devrait (probablement) pas y avoir de dates dans la dimension Activité - elles devraient toutes être dans le fait, car la clé de substitution fait référence à la dimension Date. Par exemple, une date qui resterait dans une dimension de personne serait une date de naissance car c'est un attribut d'une personne. Une date de visite à l'hôpital résiderait dans un fait, car il s'agit d'un événement ponctuel associé à une personne, entre autres choses, mais ce n'est pas un attribut de la personne visitant l'hôpital. Plus de discussion date dans le fait.

DimSite- semble simple, nous allons donc décrire les clés de substitution ici. Il s'agit essentiellement d'un ID unique incrémentiel. La colonne Identité entière est courante. Cela permet la séparation des systèmes DW et source et garantit des jointures optimales dans l'entrepôt de données. Votre clé naturelle ou votre clé commerciale est généralement conservée, mais pour la maintenance / conception, pas l'analyse et les jointures. Exemple de schéma:

CREATE TABLE [DIM].[Site]
(
 SiteSK INT NOT NULL IDENTITY PRIMARY KEY
,SiteNK INT NOT NULL --source system key
,SiteName VARCHAR(500) NOT NULL
)

DimDate- attributs de date. Créez une "clé intelligente" au lieu d'une identité. Cela signifie que vous pouvez taper un entier significatif lié à une date pour des requêtes telles que WHERE DateSK = 20150708. Il existe de nombreux scripts gratuits pour charger DimDate et la plupart ont cette clé intelligente incluse. ( une option )

DimEmployee - votre code XML l'a inclus, s'il s'agit d'un changement plus général de DimPerson, et remplissez-le avec les attributs de personne pertinents, car ils sont disponibles et pertinents pour la génération de rapports.

Et votre fait est:

FactActivitySite
DimSiteSK - FK to DimSite
DimActivitySK - FK to DimActivity
DimEmployee - FK to DimEmployee
DimDateSK - FK to DimDate

Vous pouvez les renommer dans le fait et vous pouvez avoir plusieurs clés de date par événement. Les faits sont généralement très importants, donc éviter les mises à jour est généralement bon ... si vous avez plusieurs mises à jour de dates pour un seul événement, vous pouvez essayer une conception Supprimer / Insérer en ajoutant une SK au fait qui permet la sélection de lignes de "mise à jour" pour être supprimé puis en insérant les dernières données.

Développez vos dates d'information à tout ce dont vous avez besoin: StartDateSK, EndDateSK, ScheduledStartDateSK.

Toutes les dimensions doivent avoir une ligne inconnue généralement avec un SK -1 codé en dur. Lorsque vous chargez le fait et qu'une activité n'a aucune des dates incluses, elle doit simplement charger un -1.

Le fait est une collection de références entières à vos attributs stockés dans les dimensions, joignez-les ensemble et vous obtenez toutes vos informations, dans un modèle de jointure très propre, et le fait, en raison de ses types de données, est exceptionnellement petit et rapide. Puisque vous êtes dans SQL Server, ajoutez un index columnstore pour augmenter davantage les performances. Vous pouvez simplement le supprimer et le reconstruire pendant ETL. Une fois arrivé à SQL 2014+, vous pouvez écrire dans les index columnstore.

entrez la description de l'image ici

Si vous suivez cette route, recherchez Modélisation dimensionnelle. Je recommanderais la méthodologie Kimball . Il existe également de nombreux guides gratuits, mais si ce sera autre chose qu'une solution unique, l'investissement en vaut probablement la peine.


(question de wesdev): @Dave, quel outil ERD avez-vous utilisé?
ypercubeᵀᴹ

Cela a été fait dans Microsoft Visio 2013
Dave
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.