Ich habe eine Anwendung geerbt, die einer Site viele verschiedene Arten von Aktivitäten zuordnet. Es gibt ungefähr 100 verschiedene Aktivitätstypen, und jeder hat unterschiedliche Sätze von 3-10 Feldern. Alle Aktivitäten haben jedoch mindestens ein Datumsfeld (kann eine beliebige Kombination aus Datum, Startdatum, Enddatum, geplantem Startdatum usw. sein) und ein Feld für die verantwortliche Person. Alle anderen Felder variieren stark und ein Startdatum wird nicht unbedingt als "Startdatum" bezeichnet.
Das Erstellen einer Subtyp-Tabelle für jeden Aktivitätstyp würde zu einem Schema mit 100 verschiedenen Subtyp-Tabellen führen, das zu unhandlich wäre, um es zu behandeln. Die aktuelle Lösung für dieses Problem besteht darin, die Aktivitätswerte als Schlüssel-Wert-Paare zu speichern. Dies ist ein stark vereinfachtes Schema des aktuellen Systems, um den Punkt zu vermitteln.
Jede Aktivität verfügt über mehrere ActivityFields. Jede Site verfügt über mehrere Aktivitäten, und in der SiteActivityData-Tabelle werden die KVPs für jede SiteActivity gespeichert.
Dadurch ist die (webbasierte) Anwendung sehr einfach zu codieren, da Sie lediglich die Datensätze in SiteActivityData für eine bestimmte Aktivität durchlaufen und einem Formular eine Bezeichnung und ein Eingabesteuerelement für jede Zeile hinzufügen müssen. Aber es gibt viele Probleme:
- Integrität ist schlecht; Es ist möglich, ein Feld in SiteActivityData einzufügen, das nicht zum Aktivitätstyp gehört, und DataValue ist ein Varchar-Feld, sodass Zahlen und Daten ständig umgewandelt werden müssen.
- Die Berichterstellung und Ad-hoc-Abfrage dieser Daten ist schwierig, fehleranfällig und langsam. Um beispielsweise eine Liste aller Aktivitäten eines bestimmten Typs zu erhalten, deren Enddatum innerhalb eines bestimmten Bereichs liegt, müssen Pivots und Varchars auf Datumsangaben gesetzt werden. Die Verfasser von Berichten HASSEN dieses Schema, und ich beschuldige sie nicht.
Ich suche also nach einer Möglichkeit, eine große Anzahl von Aktivitäten, die fast keine gemeinsamen Felder haben, so zu speichern, dass die Berichterstellung einfacher wird. Was ich mir bisher ausgedacht habe, ist die Verwendung von XML zum Speichern der Aktivitätsdaten in einem Pseudo-NoSQL-Format:
Die Aktivitätstabelle würde die XSD für jede Aktivität enthalten, sodass die ActivityField-Tabelle nicht mehr erforderlich ist. SiteActivity würde das Schlüsselwert-XML enthalten, sodass sich jede Aktivität für eine Site jetzt in einer einzelnen Zeile befindet.
Eine Aktivität würde ungefähr so aussehen (aber ich habe sie nicht vollständig ausgearbeitet):
<SomeActivityType>
<SomeDateField type="StartDate">2000-01-01</SomeDateField>
<AnotherDateField type="EndDate">2011-01-01</AnotherDateField>
<EmployeeId type="ResponsiblePerson">1234</EmployeeId>
<SomeTextField>blah blah</SomeTextField>
...
Vorteile:
- Die XSD würde das XML validieren und Fehler wie das Einfügen einer Zeichenfolge in ein Zahlenfeld auf Datenbankebene abfangen, was mit dem alten Schema, in dem alles in varchar gespeichert war, unmöglich war.
- Das Recordset von KVPs, das zum Erstellen der Webformulare verwendet wird, kann problemlos mit reproduziert werden
select ... from ActivityXML.nodes('/SomeActivityType/*') as T(r)
- Eine xpath-Unterabfrage des XML kann verwendet werden, um eine Ergebnismenge zu erstellen, die Spalten für Startdatum, Enddatum usw. enthält, ohne einen Pivot zu verwenden
select ActivityXML.value('.[@type=StartDate]', 'datetime') as StartDate, ActivityXML.value('.[@type=EndDate]', 'datetime') as EndDate from SiteActivity where...
Scheint dies eine gute Idee zu sein? Ich kann mir keine anderen Möglichkeiten vorstellen, eine so große Anzahl unterschiedlicher Eigenschaften zu speichern. Ein anderer Gedanke, den ich hatte, war, das vorhandene Schema beizubehalten und es in etwas zu übersetzen, das in einem Data Warehouse leichter abfragbar ist, aber ich habe noch nie ein Sternschema entworfen und hätte keine Ahnung, wo ich anfangen soll.
Zusätzliche Frage: Wenn ich ein Tag mit einem Datumsdatentyp in der XSD definiere xs:date
, wird SQL Server es dann als Datumswert indizieren? Ich bin besorgt, wenn ich nach Datum abfrage, muss die Datumszeichenfolge in einen Datumswert umgewandelt werden, und es besteht keine Chance, einen Index zu verwenden.