Eu herdei um aplicativo que associa muitos tipos diferentes de atividades a um site. Existem aproximadamente 100 tipos de atividades diferentes e cada um possui um conjunto diferente de 3 a 10 campos. No entanto, todas as atividades têm pelo menos um campo de data (pode ser qualquer combinação de data, data de início, data de término, data de início agendada etc.) e um campo de pessoa responsável. Todos os outros campos variam amplamente e um campo de data de início não será necessariamente chamado de "Data de início".
Criar uma tabela de subtipos para cada tipo de atividade resultaria em um esquema com 100 tabelas de subtipos diferentes, o que seria muito difícil de lidar. A solução atual para esse problema é armazenar os valores da atividade como pares de valores-chave. Este é um esquema bastante simplificado do sistema atual para entender o ponto.
Cada atividade possui vários ActivityFields; cada site possui várias atividades e a tabela SiteActivityData armazena os KVPs de cada SiteActivity.
Isso torna o aplicativo (baseado na Web) muito fácil de codificar, porque tudo o que você realmente precisa fazer é percorrer os registros no SiteActivityData para uma determinada atividade e adicionar um controle de rótulo e entrada para cada linha a um formulário. Mas há muitos problemas:
- Integridade é ruim; é possível inserir um campo no SiteActivityData que não pertença ao tipo de atividade e o DataValue é um campo varchar, portanto, números e datas precisam ser constantemente convertidos.
- Os relatórios e consultas ad-hoc desses dados são difíceis, propensos a erros e lentos. Por exemplo, obter uma lista de todas as atividades de um determinado tipo que tenham uma Data de término dentro de um intervalo especificado requer pivôs e varchars de conversão para datas. Os redatores de relatórios odeiam esse esquema e eu não os culpo.
Então, o que estou procurando é uma maneira de armazenar um grande número de atividades que quase não têm campos em comum, de maneira a facilitar a geração de relatórios. O que eu vim até agora é usar XML para armazenar os dados da atividade em um formato pseudo-noSQL:
A tabela Atividade conteria o XSD para cada atividade, eliminando a necessidade da tabela ActivityField. SiteActivity conteria o XML de valor-chave, para que cada atividade de um site agora estivesse em uma única linha.
Uma atividade seria algo parecido com isto (mas eu não a desenvolvi completamente):
<SomeActivityType>
<SomeDateField type="StartDate">2000-01-01</SomeDateField>
<AnotherDateField type="EndDate">2011-01-01</AnotherDateField>
<EmployeeId type="ResponsiblePerson">1234</EmployeeId>
<SomeTextField>blah blah</SomeTextField>
...
Vantagens:
- O XSD validaria o XML, detectando erros como colocar uma string em um campo numérico no nível do banco de dados, algo que era impossível com o esquema antigo que armazenava tudo no varchar.
- O conjunto de registros de KVPs usado para criar formulários da Web pode ser facilmente reproduzido usando
select ... from ActivityXML.nodes('/SomeActivityType/*') as T(r)
- Uma subconsulta xpath do XML pode ser usada para produzir um conjunto de resultados que possui colunas para data de início, data de término etc. sem usar um pivô, algo como
select ActivityXML.value('.[@type=StartDate]', 'datetime') as StartDate, ActivityXML.value('.[@type=EndDate]', 'datetime') as EndDate from SiteActivity where...
Parece uma boa ideia? Não consigo pensar em outras maneiras de armazenar um número tão grande de diferentes conjuntos de propriedades. Outro pensamento que tive foi manter o esquema existente e convertê-lo em algo mais facilmente consultável em um data warehouse, mas nunca projetei um esquema em estrela antes e não fazia ideia de por onde começar.
Pergunta adicional: Se eu definir uma marca como tendo um tipo de dados de data no XSD xs:date
, o SQL Server o indexará como um valor de data? Estou preocupado se, se eu consultar por data, ele precisará converter a string de data em um valor de data e aumentar a chance de usar um índice.