Ho ereditato un'applicazione che associa molti diversi tipi di attività a un sito. Esistono circa 100 diversi tipi di attività e ognuno ha un set diverso di 3-10 campi. Tuttavia, tutte le attività hanno almeno un campo data (potrebbe essere qualsiasi combinazione di data, data di inizio, data di fine, data di inizio programmata, ecc.) E un campo persona responsabile. Tutti gli altri campi variano ampiamente e un campo della data di inizio non sarà necessariamente chiamato "Data di inizio".
La creazione di una tabella di sottotipi per ciascun tipo di attività comporterebbe uno schema con 100 diverse tabelle di sottotipi, che sarebbe troppo ingombrante da gestire. La soluzione attuale a questo problema è archiviare i valori dell'attività come coppie chiave-valore. Questo è uno schema molto semplificato del sistema attuale per ottenere il punto.
Ogni attività ha più ActivityField; ogni sito ha più attività e la tabella SiteActivityData memorizza i KVP per ogni SiteActivity.
Ciò rende l'applicazione (basata sul web) molto facile da codificare perché tutto ciò che è veramente necessario fare è passare in rassegna i record in SiteActivityData per una determinata attività e aggiungere un'etichetta e controllo di input per ogni riga a un modulo. Ma ci sono molti problemi:
- L'integrità è cattiva; è possibile inserire un campo in SiteActivityData che non appartiene al tipo di attività e DataValue è un campo varchar, quindi numeri e date devono essere costantemente lanciati.
- Il reporting e l'interrogazione ad hoc di questi dati è difficile, soggetto a errori e lento. Ad esempio, ottenere un elenco di tutte le attività di un determinato tipo che hanno una Data di fine in un intervallo specificato richiede pivot e trasmissione di varchars alle date. Gli autori di report odiano questo schema e non li biasimo.
Quindi quello che sto cercando è un modo per archiviare un gran numero di attività che non hanno quasi campi in comune in modo da rendere più semplice la segnalazione. Quello che ho escogitato finora è usare XML per archiviare i dati di attività in un formato pseudo-noSQL:
La tabella Attività conterrebbe l'XSD per ogni attività, eliminando la necessità della tabella ActivityField. SiteActivity conterrebbe l'XML del valore-chiave in modo che ogni attività per un sito sia ora in una singola riga.
Un'attività dovrebbe assomigliare a questa (ma non l'ho ancora completamente chiarita):
<SomeActivityType>
<SomeDateField type="StartDate">2000-01-01</SomeDateField>
<AnotherDateField type="EndDate">2011-01-01</AnotherDateField>
<EmployeeId type="ResponsiblePerson">1234</EmployeeId>
<SomeTextField>blah blah</SomeTextField>
...
vantaggi:
- L'XSD avrebbe convalidato l'XML, rilevando errori come mettere una stringa in un campo numerico a livello di database, cosa impossibile con il vecchio schema che memorizzava tutto in varchar.
- Il recordset di KVP utilizzato per creare i moduli Web può essere facilmente riprodotto utilizzando
select ... from ActivityXML.nodes('/SomeActivityType/*') as T(r)
- Una sottoquery xpath dell'XML potrebbe essere utilizzata per produrre un set di risultati con colonne per la data di inizio, la data di fine, ecc. Senza usare un perno, qualcosa come
select ActivityXML.value('.[@type=StartDate]', 'datetime') as StartDate, ActivityXML.value('.[@type=EndDate]', 'datetime') as EndDate from SiteActivity where...
Ti sembra una buona idea? Non riesco a pensare ad altri modi per memorizzare un numero così elevato di insiemi di proprietà differenti. Un altro pensiero che avevo era mantenere lo schema esistente e tradurlo in qualcosa di più facilmente interrogabile in un data warehouse, ma non avevo mai progettato uno schema a stella prima e non avrei idea da dove cominciare.
Domanda aggiuntiva: se definisco un tag con un tipo di dati di data nell'XSD xs:date
, SQL Server lo indicizzerà come valore di data? Sono preoccupato se eseguo una query per data, sarà necessario eseguire il cast della stringa della data su un valore di data e aumentare le possibilità di utilizzare un indice.