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.
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:
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.