一个项目的生命在很大程度上取决于一开始对对象模型和基础结构的思考程度。
公认的方法已经并且仍然是将“星型”方案与第三范式组合的各种选择。通常,根据以下原则:初始数据-3NF,展示柜-星形。这种经过时间考验的方法得到了大量研究的支持,是经验丰富的DWH人员在考虑分析存储库的外观时首先想到的(有时是唯一的)。
另一方面,总体业务尤其是客户需求往往会快速变化,数据“深度”和“广度”都在增长。这就是恒星的主要缺点所在,即柔韧性有限。
如果您在作为DWH开发人员的安静舒适的生活中,突然:
- 任务出现了“至少很快地做点什么,然后我们会看到的”;
- 一个迅速发展的项目出现了,每周至少一次与新资源的连接和业务模型的重新设计;
- 出现了一位客户,他不知道系统的外观和最终应执行的功能,但准备进行实验并采用一致的方法对所需结果进行一致的改进;
- 项目经理听到了一个好消息:“现在我们有了敏捷!”
或者,如果您只是想知道如何建立存储空间,欢迎您的光临!
灵活性是什么意思?
首先,让我们定义一个系统必须具有的属性才能被称为“灵活的”。
另外,应注意,所描述的属性应专门与系统有关,而不与系统开发过程有关。因此,如果您想了解敏捷作为一种开发方法,最好阅读其他文章。例如,就在哈布雷(Habré)上,有很多有趣的材料(概述和实用,以及有问题的)。
这并不意味着CD的开发过程和结构完全没有联系。通常,开发具有灵活体系结构的敏捷存储应该容易得多。但是,实际上,由Kimball进行的经典DWH的敏捷开发和由Waterfall进行的DataVault的开发有更多的选择,而不是其在一个项目中的两个假设的灵活性的巧合。
那么,灵活存储应具备哪些功能?这里有三点:
- 尽早交付和快速跟进意味着理想情况下,应尽早(即,甚至在完整设计和实施整个系统之前)收到第一份业务结果(例如,第一份工作报告)。此外,每次后续修订也应花费尽可能少的时间。
- — , . — , , . , , — .
- 不断适应不断变化的业务需求-在设计总体对象结构时,不仅应考虑可能的扩展,还应期望下一次扩展的方向在设计阶段甚至不会让您梦想。
是的,在一个系统中满足所有这些要求是可能的(当然,在某些情况下并有一些警告)。
下面,我将考虑两种最流行的用于HD的敏捷设计方法-锚模型和Data Vault。... 方括号后面是诸如EAV,6NF(以纯格式显示)之类的出色技术以及与NoSQL解决方案相关的所有内容-不是因为它们在某种程度上更糟,甚至不是因为在这种情况下,这篇文章可能威胁要获取平均值Dissera。仅仅是所有这些都是针对稍有不同的类的解决方案-涉及可以在特定情况下应用的技术,而不管项目的总体架构(例如EAV),还是全局性的其他信息存储范例(例如图形数据库和其他选项) NoSQL)。
敏捷方法论中“经典”方法的问题及其解决方案
我所说的“经典”方法是指好老星(不管底层的具体实现如何,金博尔,因蒙和CDM的追随者都可以原谅我)。
1.关系的刚性基数
该模型基于将数据清楚地分为维度(Dimension)和事实(Fact)的基础。而且,该死的,这是合乎逻辑的-毕竟,绝大多数情况下的数据分析都归结为某些部分(维度)中某些数字指标(事实)的分析。
在这种情况下,对象之间的链接通过外键以表之间的链接的形式放置。这看起来很自然,但是它立即导致了灵活性的第一个限制-对连接基数的严格定义。
这意味着在表的设计阶段,必须为每对相关对象精确定义它们是多对多还是仅一对多,并且“朝哪个方向”。这将直接确定哪些表将具有主键,哪些将具有外部键。在收到新要求时改变这种态度很可能会导致基地的重新设计。
例如,在设计“收银机支票”对象时,您依靠销售部门的誓言,确定了一项促销活动可以作用于多个支票职位的可能性(反之则不行):
过了一会儿,同事们提出了一种新的营销策略,在该策略中,多个促销可以同时作用于同一位置。现在,您需要通过选择链接到一个单独的对象中来修改表。
(现在还需要改进所有进行促销检查的派生对象)。
数据保管库和锚定模型中的链接
事实证明,避免这种情况非常简单:您
这种方法是Dan Linstedt提出的,它是Data Vault范式的一部分,并得到了LarsRönnbäck在Anchor模型中的完全支持。
结果,我们获得了敏捷方法论的第一个特色:
对象之间的关系不存储在父实体的属性中,而是一种单独的对象类型。该数据保险库是表韧带称为链接,并在锚模型-的领带。乍一看,它们非常相似,尽管它们的区别不仅限于名称(将在下面讨论)。在两种体系结构中,链接表都可以链接任意数量的实体(不一定是2)。
乍一看,这种冗余为修改提供了极大的灵活性。这样的结构不仅可以更改现有链接的基数,而且可以添加新的链接-如果现在支票位置也具有与打孔的收银员的链接,则这种链接的外观将简单地成为现有表的附加组件,而不会影响任何现有对象,并且流程。
2.数据重复
通过灵活的体系结构解决的第二个问题不太明显,并且主要是SCD2类型的测量(第二类型的尺寸缓慢变化)固有的,尽管不仅是它们固有的。
在经典商店中,维通常是一个表,该表在单独的列中包含代理键(如PK)以及一组业务键和属性。
如果对维度进行了版本控制,则会将版本时限添加到标准字段集,并且存储中源中的每行会显示多个版本(对版本化属性的每次更改都对应一个)。
如果一个维度至少包含一个经常更改的版本化属性,则该维度的版本数量将非常可观(即使其他属性未版本化或永不更改),并且如果有多个此类属性,则版本数量可以从其数量呈指数增长。尽管存储在其中的大多数数据只是来自其他行的未更改属性的重复值,但这样的维度可能会占用大量磁盘空间。
同时,也非常经常使用非规范化-有些属性是有意存储为值的,而不是对目录或其他维度的引用。此方法通过减少访问维度时的联接数来加快数据访问速度。
通常,这导致以下事实:相同的信息同时存储在多个位置。例如,关于居住地区并属于客户类别的信息可以同时存储在维度“客户”和事实“购买”,“交付”和“致电呼叫中心”以及链接表“客户-客户经理”中。
通常,以上内容适用于常规(非版本化)度量,但是在版本化度量中,它们可以具有不同的比例:对象新版本的出现(尤其是事后看来)不仅导致更新所有相关表,而且导致相关对象新版本的级联出现-当使用表1构造表2时,使用表2构造表3等。即使表1的任何属性都不参与表3的构造(并且不涉及从其他来源获得的表2的其他属性),对此构造的版本更新也将至少导致额外的开销成本,最多-导致表3中不必要的版本。与它无关,甚至与整个链无关。
3.修订的非线性复杂性
此外,每个新集市都建立在另一个集市上,从而增加了对ETL进行更改时数据可以“分散”的位置。反过来,这导致每个后续修订的复杂性(和持续时间)的增加。
如果以上内容涉及很少修改ETL流程的系统,那么您可以采用这种范例-您只需要确保将新的修改正确地引入到所有相关对象中即可。如果经常进行修订,则意外“丢失”多个连接的可能性会大大增加。
此外,如果我们考虑到“版本化”的ETL比“非版本化”的ETL要复杂得多,那么在整个经济体系的频繁修订中,避免错误就变得非常困难。
在Data Vault和Anchor模型中存储对象和属性
敏捷架构的作者提出的方法可以表述为:
有必要将变化与保持不变分开。即,将键与属性分开。同时,不应将未版本化的属性与未更改的属性混为一谈:第一个属性不存储更改历史记录,但可以更改(例如,当输入错误得到纠正或接收到新数据时);第二个属性永不更改。
在数据保管库和锚定模型中,什么才可以被视为不变的观点有所不同。
从Data Vault体系结构的角度来看,整个密钥集可以认为是不变的-自然的(组织的TIN,源系统中的产品代码等)并可以替代。同时,其余属性可以按更改的源和/或更改频率分为几组,并且可以为每个组维护一个具有独立版本集的单独表。
在范式中锚模型被认为是唯一不变的实体代理密钥。其他所有内容(包括自然键)只是其属性的特例。同时,所有属性默认情况下都是彼此独立的,因此,必须为每个属性创建一个单独的表。
在Data Vault中,包含实体键的表称为Hubs。集线器始终包含一组固定的字段:
- 实体自然键
- 代理键
- 链接到源
- 记录添加时间
集线器中的条目永远不会更改并且没有版本。从外观上看,集线器与某些系统中用于生成代理的ID映射类型的表非常相似,但是,建议不要使用整数序列作为Data Vault中的代理,而应使用一组业务密钥中的哈希。这种方法简化了源代码中链接和属性的加载(您无需加入集线器即可获得代理,只需从自然键计算哈希值),但会导致其他问题(例如与冲突,字符串键中的大小写和不可打印字符等有关)。 .p。),因此通常不接受。
实体的所有其他属性都存储在称为“卫星”的特殊表中...一个集线器可以有几颗存储不同属性集的卫星。
卫星之间属性的分配基于共同更改的原则-一颗卫星可以存储非版本属性(例如,个人的出生日期和SNILS),而另一颗卫星-存储很少更改版本的属性(例如,姓氏和护照号码),在第三颗中通常-更改(例如,送货地址,类别,最后订购日期等)。在这种情况下,版本控制是在单个卫星而不是整个实体的级别上进行的;因此,建议分配属性,以使一个卫星内的版本相交最小(这减少了存储版本的总数)。
另外,为了优化数据加载过程,通常将从不同来源获得的属性放在单独的卫星中。
卫星使用外键(对应于一对多基数)与集线器通信。这意味着此``默认''体系结构支持多个属性值(例如,一个客户的多个联系电话号码)。
在Anchor模型中,持有键的表称为Anchor。他们保持:
- 仅代理键
- 链接到源
- 记录添加时间
从锚模型的角度来看,自然键被视为普通属性。这个选项似乎很难理解,但是它为对象识别提供了更多的空间。
例如,如果有关同一实体的数据可以来自不同的系统,则每个系统都使用自己的自然键。在Data Vault中,这可能会导致多个集线器的结构繁琐(每个源一个+统一主版本),而在Anchor模型中,每个源的自然键都属于其自己的属性,并且可以在加载期间独立于所有其他源使用。
但是这里有一个隐患:如果将来自不同系统的属性合并到一个实体中,则很可能存在一些隐患。“粘合”规则,系统必须根据该规则理解来自不同来源的记录对应于一个实体的一个实例。
在Data Vault中,这些规则很可能会确定主实体的“代理中心”的形成,并且不会以任何方式影响存储源自然键及其初始属性的中心。如果在某个时候更改了拼接规则(或对其进行了属性的更新),则足以重新形成代理中心。但是,
在锚模型中,这样的实体很可能存储在单个锚中。...这意味着所有属性,无论它们来自哪个来源,都将绑定到相同的代理。分离错误合并的记录并通常很难跟踪这种系统中合并的相关性,尤其是在规则足够复杂且经常更改并且可以从不同来源获得相同属性的情况下(尤其是如果规则可能,因为每个属性版本保留指向其源的链接)。
无论如何,如果您的系统应该实现重复数据删除功能,合并记录和其他MDM元素,值得仔细研究一下敏捷方法中存储自然键的各个方面。就合并错误而言,更麻烦的Data Vault设计可能突然证明更安全。
锚点模型还提供了另一种称为“结”的对象,实际上,它是一种特殊的简并锚点,只能包含一个属性。这些节点应该用于存储平面参考书(例如,性别,婚姻状况,客户服务类别等)。与Anchor不同,Node没有关联的属性表,其唯一属性(名称)始终与键存储在同一表中。节点通过Tie表链接到Anchors,就像锚点彼此链接一样。
对于节点的使用没有明确的意见。例如,正在俄罗斯积极推广使用Anchor模型的尼古拉·戈洛夫(Nikolai Golov)相信(并非没有道理)没有参考书是不可能肯定地说它永远是静态的并且是单层的,因此最好一次对所有对象使用成熟的Anchor。
Data Vault和Anchor模型之间的另一个重要区别是链接的属性是否存在:
在Data Vault中,链接是与集线器相同的完整对象,并且可以具有自己的属性。在Anchor模型中,链接仅用于连接Anchor,而不能具有自己的属性。这种差异为建模事实提供了截然不同的方法,下面将对此进行讨论。
储存事实
在此之前,我们主要讨论了建模测量。有了事实,情况就不那么简单了。
在Data Vault中,用于存储事实的典型对象是Link,在Satellite中添加了真实指示符。
这种方法看起来很直观。它提供了对已分析指标的轻松访问,并且通常类似于传统的事实表(仅指标不存储在表本身中,而是存储在“相邻”表中)。但是也有陷阱:典型的模型修改之一-扩展事实密钥-必须向Link添加新的外键。而这进而“破坏”了模块性,并可能导致需要改进其他对象。
在锚模型中链接不能拥有自己的属性,因此这种方法将行不通-绝对所有的属性和指示符都必须绑定到一个特定的锚点。由此得出的结论很简单-每个事实也都需要自己的锚点。对于我们习惯作为事实的一部分,它看起来很自然-例如,将购买的事实完全简化为对象“订单”或“收据”,对网站的访问-会话等。但是,对于某些事实,要找到这样一个自然的“承运人对象”并非易事-例如,每天开始时仓库中的货物残骸。
因此,在Anchor模型中扩展事实密钥时,模块性没有问题(您只需要向相应的Anchor添加新的链接),但是用于显示事实的模型设计就不太明确了,可能会出现反映业务对象模型的``人工''Anchor并不明显。
如何实现灵活性
在这两种情况下,最终的构造都包含比传统维度更多的表。但是,与传统维度相比,具有相同版本属性的集合可以占用更少的磁盘空间。自然,这里没有魔力-一切都与规范化有关。通过跨卫星(在Data Vault中)或单独的表(锚模型)中分布属性,我们可以在更改其他属性时减少(或完全消除)一些属性值的重复。
对于Data Vault,其增益将取决于卫星之间的属性分布,对于Anchor模型,其增益将几乎与每个测量对象的平均版本数成正比。
但是,获得空间是重要的但不是单独存储属性的主要优点。与单独存储链接一起,这种方法使存储库成为模块化设计。这意味着除了包括个人属性和全新的学科领域在这样的模式看起来像一个的添加-就在现有的一组对象而不改变他们。这正是使所描述的方法灵活的原因。
它还类似于从样件生产到批量生产的过渡-如果在传统方法中每个模型表都是唯一的并且需要单独关注,那么在灵活的方法中,它已经是一组典型的“细节”。一方面,有更多的表,加载和获取数据的过程看起来应该更复杂。另一方面,它们变得很典型。这意味着它们可以由元数据自动化和管理。问题“我们将如何铺设它?”的答案可能会占用改进设计工作的很大一部分,现在根本不值得(以及模型更改对工作流程的影响问题)。
这并不意味着根本就不需要这种系统中的分析人员-仍然有人必须研究一组具有属性的对象,并弄清楚在何处以及如何加载所有这些内容。但是,工作量以及错误的可能性和成本都大大降低了。在分析阶段和ETL开发期间,都可以简化为编辑元数据。
暗面
所有以上这些使这两种方法真正灵活,技术先进并且适用于迭代优化。当然,还有一个“药膏桶”,我想您已经在猜测了。
数据分解是灵活体系结构模块化的基础,它导致表数量的增加,并因此导致提取时联接的开销。为了简单地获取维度的所有属性,经典存储库中的一个选择就足够了,而灵活的体系结构将需要多个连接。此外,如果对于报告而言,所有这些联接都可以预先编写,那么习惯于手工编写SQL的分析师将遭受双重打击。
有几个事实使这种情况更容易:
当使用大尺寸时,几乎永远不会同时使用其所有属性。这意味着联接可能比初次查看模型时看起来要少。在Data Vault中,您还可以在跨卫星分配属性时考虑预期的共享频率。同时,集线器或锚点本身主要是在加载阶段生成和映射代理人所必需的,很少在请求中使用(特别是对于锚点)。
所有联接都是按键进行的。此外,更“简洁”的数据存储方式可以减少必要时扫描表的开销(例如,按属性值进行过滤时)。这可能导致这样的事实,即从具有一堆联接的规范化数据库中获取数据的速度甚至比扫描每行多个版本的沉重维数还要快。
例如,在这里本文章有锚模型与从单个表选择了详细的对比性能测试。
在很大程度上取决于发动机。许多现代平台都有内部联接优化机制。例如,如果MS SQL和Oracle的数据除其他联接以外没有在其他地方使用,并且不影响最终选择(表/联接消除),则MS SQL和Oracle可以“跳过”联接到表,而MPP Vertica是考虑到对查询计划的一些手动优化,Avito同事的丰富经验被证明是Anchor模型的出色引擎。另一方面,例如,将Anchor模型保留在具有有限加入支持的Click House上似乎不是一个好主意。
此外,这两种体系结构都有特殊的技术来使数据更易于访问(从查询性能和最终用户角度而言)。例如,数据保管库中的时间点表或锚模型中的特殊表功能。
总
所考虑的灵活架构的主要实质是其“设计”的模块化。
该属性允许:
这种灵活性的代价是性能。这并不意味着不可能在此类模型上获得可接受的性能。通常,您只需要付出更多的努力和对细节的关注即可实现所需的指标。
应用领域
数据保管库实体类型
阅读有关Data Vault的更多信息:
Dan Listadt的网站
有关俄语的Data Vault的全部信息
关于Habré上的Data Vault
锚模型实体类型
有关锚模型的更多信息:
锚模型创建者
的站点有关在Avito中实现锚模型的经验的文章
汇总表,其中包含所考虑方法的共同特征和不同之处: