我继承了一个将许多不同类型的活动与站点相关联的应用程序。大约有100种不同的活动类型,每一种都有3-10个字段的不同集合。但是,所有活动至少都有一个日期字段(可以是日期,开始日期,结束日期,预定开始日期等的任意组合)和一个负责人字段。所有其他字段的差异很大,开始日期字段不一定称为“开始日期”。
为每种活动类型创建一个子类型表将导致具有100个不同子类型表的模式,这太麻烦了以至于无法处理。该问题的当前解决方案是将活动值存储为键值对。这是当前系统的一个大大简化的架构,可以用来说明要点。
每个活动都有多个ActivityField;每个站点都有多个活动,并且SiteActivityData表存储每个SiteActivity的KVP。
这使基于Web的应用程序非常容易编写代码,因为您真正需要做的就是遍历SiteActivityData中给定活动的记录,并为表单的每一行添加标签和输入控件。但是有很多问题:
- 诚信不好;可以在SiteActivityData中放置一个不属于活动类型的字段,而DataValue是一个varchar字段,因此需要不断地转换数字和日期。
- 报告和临时查询此数据非常困难,容易出错且速度很慢。例如,要获得某个结束日期在指定范围内的某种类型的所有活动的列表,则需要进行数据透视并将varchars转换为日期。报表编写者讨厌这种模式,我不怪他们。
因此,我要寻找的是一种存储大量几乎没有共同字段的活动的方式,从而可以简化报告。到目前为止,我想出的是使用XML以伪noSQL格式存储活动数据:
Activity表将包含每个活动的XSD,从而无需使用ActivityField表。SiteActivity将包含键值XML,因此站点的每个活动现在都位于一行中。
一个活动看起来像这样(但是我还没有完全充实它):
<SomeActivityType>
<SomeDateField type="StartDate">2000-01-01</SomeDateField>
<AnotherDateField type="EndDate">2011-01-01</AnotherDateField>
<EmployeeId type="ResponsiblePerson">1234</EmployeeId>
<SomeTextField>blah blah</SomeTextField>
...
优点:
- XSD将验证XML,捕获错误,例如在数据库级别将字符串放入数字字段中,这对于将所有内容都存储在varchar中的旧模式是无法实现的。
- 用于构建Web表单的KVP记录集可以很容易地使用
select ... from ActivityXML.nodes('/SomeActivityType/*') as T(r)
- XML的xpath子查询可用于生成一个包含开始日期,结束日期等列的结果集,而无需使用数据透视表,例如
select ActivityXML.value('.[@type=StartDate]', 'datetime') as StartDate, ActivityXML.value('.[@type=EndDate]', 'datetime') as EndDate from SiteActivity where...
这似乎是个好主意吗?我想不出其他方式来存储大量不同的属性集。我的另一个想法是保留现有模式,并将其转换为更容易在数据仓库中查询的内容,但是我以前从未设计过星型模式,也不知道从哪里开始。
附加问题:如果我使用定义XSD中具有日期数据类型的标记xs:date
,SQL Server会将其索引为日期值吗?我担心如果我按日期查询,它将需要将日期字符串转换为日期值并浪费使用索引的任何机会。