有效地存储键值对的集合,这些键值对具有完全不同的键


9

我继承了一个将许多不同类型的活动与站点相关联的应用程序。大约有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会将其索引为日期值吗?我担心如果我按日期查询,它将需要将日期字符串转换为日期值并浪费使用索引的任何机会。


报告的数据需要如何更新?这些报告会影响生产吗?
詹姆斯·安德森

大多数报告现在都命中了一个数据仓库(实际上不是DW,它本质上是生产事务模式的副本,并添加了来自其他数据库的视图和表的碎片)。收到过时的报告是可以接受的,但是如果可以发布,那将是一个好处。
Paul Abbott

田间有多少重叠?十个字段涵盖所有100个子类型,还是大约500个完全不同的字段?
所有行业的乔恩2015年

有72个字段和75种活动类型。30个字段仅由一个活动使用,其余大部分由5-10个活动使用。大约30种不同的活动使用了少数几个字段。在大多数情况下,活动之间并没有很多共通之处。
Paul Abbott 2015年

Answers:


7

因此,我要寻找的是一种存储大量几乎没有共同字段的活动的方式,从而可以简化报告。

没有足够的代表先发表评论,所以我们开始吧!

如果主要目的是报告并且您有DW(即使它不是星型模式),我建议尝试将其纳入星型模式。好处是快速,简单的查询。缺点是ETL,但您已经在考虑将数据移至新设计,而将ETL用作星型架构则可能比XML包装器解决方案更容易构建和维护(并且SQL Server许可中包含SSIS)。此外,它还启动了公认的报告/分析设计过程。

那么该怎么做……听起来您有所谓的“ 事实”。这是定义没有关联度量(例如销售价格)的事件的属性的交集。您有部分或全部活动的可用日期吗?您可能确实应该有一个活动,站点和日期的交集。

DimActivity-我猜有一种模式,可以让您将这些模式分解为至少相对共享的列。如果是这样,您可能有三个?五?活动类别的尺寸。最坏的情况是,您会有几个一致的列,例如活动名称,可以进行过滤,并保留诸如“ Attribute1”之类的常规标题,以获取其余的随机详细信息。

您不需要维度中的所有内容-“活动”维度中(可能)不应有任何日期-实际上,它们都应是事实,因为代理键引用了Date维度。例如,保留在人维度中的日期将是出生日期,因为它是人的属性。医院访问日期将存在于事实中,因为它是与人相关联的时间点事件,但是,它不是人去医院的属性。事实更多的讨论。

DimSite-似乎很简单,因此我们将在此处描述代理键。本质上,这只是一个递增的唯一ID。整数标识列是常见的。这样可以隔离DW和源系统,并确保数据仓库中的最佳连接。通常会保留您的自然密钥或业务密钥,但是对于维护/设计,则不会进行分析和联接。模式示例:

CREATE TABLE [DIM].[Site]
(
 SiteSK INT NOT NULL IDENTITY PRIMARY KEY
,SiteNK INT NOT NULL --source system key
,SiteName VARCHAR(500) NOT NULL
)

DimDate-日期属性。制作一个“智能钥匙”而不是一个身份。这意味着您可以输入与日期相关的有意义的整数,例如WHERE DateSK =20150708。可以使用许多免费脚本来加载DimDate,并且大多数脚本都包含此智能密钥。(一种选择

DimEmployee -如果对DimPerson进行更一般的更改,您的XML包括此属性,并在相关人员属性可用且与报告相关的情况下填充相关人员属性。

您的事实是:

FactActivitySite
DimSiteSK - FK to DimSite
DimActivitySK - FK to DimActivity
DimEmployee - FK to DimEmployee
DimDateSK - FK to DimDate

您可以在事实中重命名它们,每个事件可以有多个日期键。事实通常非常大,因此通常避免更新...如果您对一个事件有多个日期更新,则可能希望通过在事实中添加一个SK来尝试“删除/插入”设计,从而可以选择“更新”行删除,然后插入最新数据。

将您的事实日期扩展为所需的任何内容: StartDateSK, EndDateSK, ScheduledStartDateSK

所有尺寸都应有一个“未知”行,通常带有一个硬编码的-1 SK。当您加载事实并且活动没有包含的任何日期时,它应该只加载-1。

事实是对存储在维度中的属性的整数引用的集合,将它们结合在一起,就可以以非常干净的联接模式获得所有详细信息,并且由于其数据类型的原因,事实是异常小巧而快速。由于您在SQL Server中,因此添加列存储索引以进一步提高性能。您可以将其删除并在ETL期间重建。使用SQL 2014+后,您可以写入列存储索引。

在此处输入图片说明

如果您走这条路线,请研究“维度建模”。我建议使用Kimball方法。也有很多免费的指南,但是如果这不是一次性解决方案,那这笔投资很值得。


(来自wesdev的问题):@Dave,您使用了什么ERD工具?
ypercubeᵀᴹ

这是在Microsoft Visio 2013中完成的
Dave
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.