7.7 数据建模与语义层
概述与动机
一个数据模型是一项关于你的数据意味着什么的决策,它先于你决定这些数据存放在何处。它为你的业务所关心的事物命名,描述这些事物的属性,以及它们之间的关系。存储、索引、文件格式和查询引擎都是后来的事。这个先后顺序之所以重要,是因为你的数据的含义比你用来保存它的任何技术都更长久。数据仓库会被替换,表格式会改变,查询引擎会来了又走,但”客户”、“订单”和”活跃用户”在所有这些变化中,必须在数年间保持同一个含义。
对小型团队而言,建模往往是隐性的。一位工程师把整个模式记在脑子里,对”营收”的共同理解之所以能够维持,只是因为只有三个人可能产生分歧。而在大型开发组织、企业和政府机构的规模上,这种非正式性会以第 7.1 章(数据战略与治理)所描述的确切方式崩塌。数十个团队构建数百张表,每张表对”会话”是什么、用户何时算作”活跃”都有自己的一套理解。两个仪表盘为同一周显示出两个不同的数字,一场领导层会议演变成一场关于谁的查询是对的争论,而不是接下来该做什么。糟糕的建模不会立刻显现。它会在数月之后以对账工作、审计失败,以及基于没有人能够解释清楚的数字所做出的决策的形式出现。
本章讲的正是如何有意识地完成这项工作。内容涵盖概念模型、逻辑模型和物理模型;实体关系建模;何时规范化、何时反规范化;建模在事务型工作负载与分析型工作负载之间的差异;用事实表和维度表进行的维度建模;以及承载每一项业务指标的唯一受治理定义的语义层。回报不是为了优雅本身。而是让”活跃用户”和”营收”在任何地方都意味着同一件事,从而让你的团队能够信任这些数字,并因此更快地行动。
另请参阅: 第 3.4 章(数据架构与存储)、第 7.3 章(分析与商业智能),以及第 11.5 章(关键绩效指标)。
关键原则
- 先决定数据意味着什么,再决定它存放在哪里。
- 分三个层级建模:概念(业务)、逻辑(结构)、物理(实现)。
- 在事务型系统中规范化以保护正确性;在分析型场景中有意识地反规范化以获得速度。
- 让模型匹配工作负载:事务处理和分析处理的需求截然相反。
- 每一项业务指标都恰好有一个受治理的定义,它存在于语义层中。
- 一致维度(conformed dimensions)让独立的团队能够安全地联结和比较数据。
- 粒度是一项你有意做出的设计决策,而不是一次查询的偶然结果。
- 模型是有生命的资产:为它们起好名字,记录文档,并保持其可演进性。
建议
按顺序分三个层级建模
从含义出发,向外展开。先从概念模型开始:你的业务关心的实体以及它们之间的关系,用一个领域专家能够核实的通俗语言写下来。“一位客户下多个订单;一个订单包含多个行项目;每个行项目指向一个产品。“此时还没有主键、没有类型、没有表。然后构建一个逻辑模型,添加结构:属性、主键和外键、基数和约束,此时仍然独立于任何具体的数据库。实体关系建模是这里的标准表示法,一张实体关系图是你与工程师和业务相关方共同评审的产物。只有到这一步,才产出物理模型:为你所选定的引擎设计实际的表、列、数据类型、索引、分区和存储布局。直接跳到物理设计是最常见的建模失误,因为它会把今天的技术选择固化进那些本应比这些技术更长久的决策之中。
规范化事务型系统,有意识地反规范化分析型系统
对于记录事务的系统,应优先采用数据库规范化。范式通过消除冗余,让每一项事实只被存储一次,从而防止更新异常,并在许多用户并发修改数据时保持写入的正确性。这是联机事务处理(OLTP)的正确默认选择,因为在这类系统中,并发写入下的正确性比任何单条分析查询的速度都更重要。分析型系统的优先级则恰恰相反。它们是读密集型的,会扫描和聚合巨大的数据范围,而在查询时联结数十张规范化的表既缓慢又难以推理。在这里,你要有意识地反规范化,把相关属性合并到一起,使查询更简单、更快速。这里的纪律在于有目的地反规范化,附带一个记录在案的理由,而不是让冗余不知不觉地渗入。第 3.4 章(数据架构与存储)涵盖了让每种模式发挥性能的引擎。
对分析场景采用维度建模
对于分析型工作负载,采用由拉尔夫·金博尔(Ralph Kimball)推广开来的方法()维度建模。你把世界拆分为事实和维度。一张事实表保存一个业务流程的度量值:一笔销售的金额、一次通话的时长、发货的数量。维度表则保存你用来筛选和分组的描述性上下文:客户、产品、门店、日期。把一张事实表安排在它的各个维度环绕之中,你就得到了一个星型模式,它便于分析师理解,也便于引擎快速查询。把这些维度进一步规范化为子表,你就得到了一个雪花模式,它以更多的联结和更高的复杂度为代价节省了一些存储空间;除非有具体理由,否则应优先选择星型模式。对于审计能力和来源追踪至关重要的超大型、强监管环境,数据仓库(data vault)方法通过建模中枢(hub)、链接(link)和卫星(satellite)来积极地捕获历史和血缘,代价是更多的表和更陡峭的学习曲线。大多数团队应当从金博尔式的星型模式起步,只有在审计要求足以支撑其代价时,才转向数据仓库方法。
明确固定粒度,并显式处理变化的维度
在向一张事实表添加任何一列之前,先说明它的粒度:一行究竟代表什么。“每个订单行项目一行。""每位用户每天一行。“粒度是一个正确模型的基础,因为每一项度量、每一个维度要么符合这个粒度,要么就不属于这张表。混合粒度正是营收被重复计算的根源。然后决定维度随时间如何变化。一位客户搬到了新城市;你是覆盖旧值,还是保留完整历史,或者只跟踪当前值和前一个值?这些是标准的缓变维度模式,选错了就意味着你的历史报表会在悄无声息中改写过去。要提前决定粒度和变化策略,把它们写入模型文档,并在评审中坚守这条底线。
构建一个语义层,作为每项指标的唯一定义
这是让整章内容物有所值的建议。语义层位于你的物理表和消费这些表的每一个工具之间,承载着每一项业务指标唯一受治理的定义。“活跃用户”只被定义一次,以代码的形式,附带其确切逻辑:哪些事件算数、在多长的时间窗口内、排除哪些内部账户。“营收”也只被定义一次,包括退款、折扣和货币换算如何处理。每一个仪表盘、笔记本、报表和反向 ETL 任务都读取这个定义,而不是在自定义查询中重新实现一遍。当定义发生变化时,它只在一个地方改变,所有消费方随之一同更新。正是这一机制让受治理的指标定义变得真实,而非纸上谈兵,它也是对第 11.5 章(关键绩效指标)所提要求的直接落地实现。要把指标定义当作有版本、有负责人、经过评审和测试的代码来对待,正如第 7.1 章要求你把数据当作一种产品来对待一样。
建立约定、命名规范和文档
一致性本身就是一项功能。采用命名约定并强制执行:表名的约定、主键的约定、日期列的标准,以及如何标记一张表是事实表还是维度表的规则。一次性决定你使用单数还是复数的实体名称,并永远不要混用。把每个模型的文档记录在使用者会去查阅的地方:每张表的含义、每张事实表的粒度、每项指标的定义,以及各自的负责人。良好的命名和文档正是让一位新分析师能够自助查阅而不必打断团队的原因,也是让审计员能够不靠人带路、就能把董事会材料中的一个数字一路追溯回其来源的原因。
让模型保持可演进性
你的模型会发生变化,因此要为变化而设计。添加新列,而不是挪用已有的列去承担新用途。使用代理键(surrogate key),这样源系统自然键的一次变化就不会波及你整个数据仓库。为指标定义设置版本,提前通知后再弃用它们,而不是在正在运行的仪表盘底下悄悄改动。把转换逻辑保存在版本控制中,接受测试和评审,这样”活跃用户”含义的一次变更就是一个带有差异对比和审批人的拉取请求,而不是在 BI 工具里的一次悄然编辑。一个无法被安全演进的模型,会变成一个人们绕道而行的模型,而影子定义正是唯一真相来源走向消亡的方式。
权衡:利与弊
| 方式 | 优点 | 缺点 | 最适场景 |
|---|---|---|---|
| 规范化(第三范式) | 写入正确,无冗余,灵活 | 分析型联结缓慢,查询复杂 | OLTP 和运营系统 |
| 星型模式(金博尔式) | 快速、直观、对分析师友好 | 存在一定冗余,需要维护 ETL | 大多数分析和 BI 场景 |
| 雪花模式 | 存储更少,维度更清晰 | 联结更多,复杂度更高 | 大型、治理严格的维度 |
| 数据仓库(Data vault) | 完整历史,可审计,加载灵活 | 表数量多,学习曲线陡峭 | 强监管、审计要求高的场景 |
| 模型之上的语义层 | 处处统一定义,与工具无关 | 前期构建投入大,需要专人负责 | 多团队、多工具的组织 |
核心张力在于单条查询的速度与整个体系范围内的正确性和灵活性之间的对抗。规范化保护了正确性,代价是查询复杂度;维度模型换来了查询速度和清晰度,代价是 ETL 以及一定程度上的受控冗余。这里没有一个放之四海而皆准的赢家,这正是为什么你应当让模型匹配工作负载,而不是选定一个偏好的方案。语义层解决的是第二重张力,即众多团队与众多工具之间的张力,方法是让指标定义独立于其中任何一个工具或团队。常见的错误是把这些方式当作互相对立的阵营。一个健康的组织会同时运行规范化的 OLTP 系统、由其供给数据的维度分析模型,以及其上的一个语义层,各自完成自己擅长的工作。
与团队讨论的问题
当两个仪表盘为同一项指标显示出不同的数字时,谁的定义说了算,那个定义实际存放在哪里? 这个问题揭示的是你是否真正拥有一个单一真相来源,还是仅仅自以为拥有。在大多数大型团队中,诚实的答案是”活跃用户”在十几个不同的查询中被重新定义过,胜出的往往是会议上声音最大的那个人。带上真实的证据:挑一项指标,找出它被计算的每一处地方,逐行比较其逻辑。你几乎一定会发现关于时间窗口、排除条件和边界情形的无声分歧。这个答案应当推动你构建一个语义层,让每项指标只被定义一次,以经过评审的代码形式存在,这样这个问题就不再关乎人,而是关乎一个有版本的产物。在那个定义拥有唯一的物理归宿之前,每一次对账都只是暂时的。
你最重要的事实表的粒度是什么,房间里的每个人能否用同样的方式陈述它? 粒度是绝大多数建模失误最终追溯到的那个安静的根基。如果团队中一半人说”每个订单一行”,另一半人说”每个行项目一行”,那么一个重复计数的缺陷已经在等待着在营收报表中浮现。带上实际的表,让每个人用一句话描述其中的一行。这里的分歧不是一个需要被抚平的沟通问题;而是一个必须在更多度量堆叠上去之前修复的设计缺陷。答案应当被写入模型文档,并在评审中强制执行,因为一旦分析师在一个含糊不清的粒度之上构建了查询,这种含糊会以你来不及纠正的速度扩散开来。
这个模型将如何吸收变化,当一项定义发生变化时,去年的报表会怎样? 每个模型都会面对不断变化的源系统、不断变化的业务规则和不断变化的指标定义,因此真正的问题在于变化是一个受控的拉取请求,还是一次悄悄改写历史的无声编辑。带上一个最近的例子:一项指标的定义曾发生过变化,或者一个源键曾被重命名,追溯一下已有的仪表盘发生了什么。如果一个缓变维度是通过覆盖来处理的,那么你的历史报表可能已经在无声中改变了它们的历史数值,这对任何做趋势分析或受监管报告的人来说都是一个严重的问题。答案应当推动你走向代理键、有版本的指标定义、显式的变化策略,以及保存在版本控制中并经过评审的转换逻辑。一个没有人能安全修改的模型,会变成一个被人们抛弃的模型。
哪些维度必须在每个团队之间意味着同一件事,谁对负责维护每一个这样的维度负责? 一致维度正是让市场、财务和运营部门能够联结各自的数据、得到可比较答案的关键,但前提是”客户”、“产品”、“地区”和”日期”承载着一个共同商定的定义,而不是每个团队各自的私有副本。与之相抗衡的是自主性:每个团队都希望以自己的节奏建模自己的世界,而强制推行一个共享维度会在短期内拖慢他们的速度,尽管这在整个体系范围内是划算的。带上在最多跨团队报表中出现的两三个维度,列出每一个维度当前存在的每一个版本,看看它们的键和属性实际上分歧到了什么程度。为每一个一致维度指定一位负责人,因为一个没有负责人的共享维度会在一个季度之内重新退化为各自的私有副本。在企业和政府场景中,当一个部门的数字要与另一个部门的数字公开对比时,一个未经一致化处理的维度,正是诚实比较与无意造假之间的分野,因此要及早决定哪些维度由中心统一治理,哪些维度保留在本地。
你规范化的事务型系统与反规范化的分析型模型之间的边界划在哪里,每一次反规范化是否都是一次有意识的决策? 让模型匹配工作负载是核心纪律,但边界恰恰是它最容易模糊的地方:一位分析师为了速度而反规范化了一张仓库表,一位工程师出于习惯而规范化了一张报表用的表,而没有人写下来每一种选择应当归属于哪一边。这里的张力是单条查询的速度与整体的正确性和灵活性之间的对抗,通情达理的人会因其所有者关注的是写入还是读取而落在不同的立场上。带上你最慢的分析查询和争用最激烈的事务型表,对每一列冗余都追问:它的冗余是出于一个记录在案的理由被选择的,还是不知不觉渗入的?目标是形成一条书面规则,规定何时允许反规范化、由谁签字,而不是一场纯粹性的比拼。对于大型或受监管的组织,这条边界还决定着个人数据在何处被复制,因此一次未经记录的反规范化既是一个性能问题,也是一个数据治理层面的风险敞口,终将有人不得不向审计员解释清楚。
语义层应当自建还是外购,一旦建成,由谁对保持每一项指标定义的最新性负责? 语义层只有在被拥有和维护的情况下,才能真正交付一个单一真相来源,因此工具的选择远不如”谁来评审对’营收’含义的一次变更、谁在定义过时时承担责任”这个问题重要。这里存在真实的相互竞争的考量:自建能给你控制权,并与你的技术栈相契合,但会增加工程负担;外购一个指标工具则更快,但存在锁定风险和一门你无法完全掌控的定义语言。带上你少数几项利害关系最高的指标、当前消费它们的工具,以及一个诚实的判断()当前是否真有人拥有这些定义,还是它们只是碰巧存在。要提前决定定义是否以有版本的代码形式存在,配有具名负责人和测试,因为一个没有人维护的语义层,会腐烂成它原本要取代的那种分散定义。在企业和政府的报告场景中,公开仪表盘上的一项指标必须能够追溯到一个记录在案、经过评审的定义,这种归属关系以及证明一个数字的血缘的能力,正是让语义层从一种便利变成一项可审计管控的关键所在。
行业视角
初创企业。 建模可以等待,但定义不能等。在只有两名工程师、没有余力搭建一个数据仓库的情况下,把一个小型语义层放进你的转换工具中,把董事会真正关注的两三项指标()“活跃用户”和”营收”()以经过测试的代码形式定义一次。跳过数据仓库方法和精心设计的维度模式;一个精简的星型模式和少数几个受治理的定义,能在不拖慢交付速度的前提下为你换来一致的数字。回报是董事会材料准备工作不再是一场关于谁的查询是对的争论。
中小企业。 你没有专职的数据建模师,也没有购买指标平台的预算,因此应依靠你已经在使用的工具内置的定义,把真正重要的几项定义写进一份所有人都会阅读的共享文档中。相比自建一个你无力配备人手维护的数据仓库,更应优先外购嵌入在现有软件中的分析能力。在确实需要建模的地方,保持简单,并一致地命名事物,因为明年维护它的人,可能正是那位记不清为什么”客户”曾经有过两种含义的人。一致性比事后对账更便宜。
大型企业。 问题在于众多团队和众多工具正在不知不觉地漂移向各自私有的定义,因此应投资于一致维度、一个受治理的统一语义层,以及以有版本代码形式存在、配有负责人和评审的指标定义。在整个体系范围内统一命名规范、粒度声明和缓变维度策略,使得一个工具中的数字与另一个工具中的同一数字相符。把语义层当作一个拥有路线图和负责团队的产品来对待,并衡量它减少了多少对账时间。回报是全公司范围内可信赖的数字,以及能够从董事会材料清晰追溯回数据来源的审计。
政府。 透明度和跨机构可比性塑造着这项工作:地理和人口统计方面的权威参考数据、核心指标的受治理定义,以及公开发布的方法论和带版本的发布记录,使公众能够将任何数字追溯回一个记录在案的定义。采购规则可能要求你的模型和定义保持可移植、厂商中立,因此应避免一个被锁定在某一专有工具上的语义层。让各机构在建模自身运营数据方面保持自由,同时在任何要在全国范围内报告的内容上遵从共享维度。一项无法追溯到有版本定义的公开指标,既是一次问责失败,也是一次数据失败。
示例
初创企业。 一家 A 轮公司的”活跃用户”存在三种定义,分别存放在三个地方:产品分析工具、财务电子表格,以及投资人材料。这些数字从未一致过,每一次董事会材料的准备都变成一场手忙脚乱。两名工程师在他们的转换工具中引入了一个小型语义层,把”活跃用户”和”月度经常性收入”以经过测试的代码形式各定义一次,写下确切的时间窗口和排除条件。现在每一个仪表盘都读取这些定义。董事会材料准备工作中的争论消失了,新分析师的入职过程也从一周的口口相传知识,变成了阅读一个有文档记录的模型。这与第 7.4 章(产品分析与实验)所描述的纪律直接相关,在那里,“活跃”的一个稳定定义正是让实验结果可比较的关键。
大型企业。 一家全球零售商在市场、财务、供应链、商品管理和门店部门运行着五种商业智能工具,每一个都以略有不同的方式重新发明了”毛利率”。他们在一个金博尔式的数据仓库之上构建了一个统一语义层,配有一致维度,使得”产品”、“门店”和”日期”在每一张事实表和每一个工具中都意味着同一件事。每项指标只被定义一次,处处消费。过去每季度要耗费数日的对账会议大多消失了,当财务部门改变了退货影响毛利率的方式时,这个变化一次性传播到了全部五个工具中。正是一致维度让独立的团队能够放心地联结彼此的数据,而不是心存疑虑。
政府。 一个国家政府需要跨卫生、劳动和教育机构进行可比较的报告,而这些机构历来各自以自己的方式定义”家庭”、“地区”和”就业”。一个跨机构机构建立了共享参考数据和标准定义:地理和人口统计方面的权威维度表,以及核心指标的受治理定义,连同方法论和带版本的发布记录一并公开。各机构继续以自己的方式建模自身的运营数据,但在任何要向全国报告的内容上,遵从共享维度和定义。结果是一个机构的数字能够与另一个机构的数字诚实地进行比较,公众也能将任何已发布的指标追溯回一个记录在案的定义,支持了第 7.1 章所涵盖的透明度义务。
商业案例:动机、投资回报率与总拥有成本
良好建模和一个语义层的回报,主要体现为省下来的时间和避免掉的错误。在许多组织中,分析师的大部分时间都花在寻找数据、对账互相矛盾的数字,以及重新构建别人早已写过的定义上。每项指标的一个受治理的统一定义,能把这种重复劳动变成一次性投入。它还消除了一整类代价高昂的失败:董事会材料中的错误数字、触发审计发现的误报数字,以及仅仅因为两个团队对”营收”定义不同而存在的、耗时一个季度的对账项目。当定义存放在一个经过评审的地方时,这些失败大多不再发生。
代价是真实存在的,值得明确说出来。你需要在概念和逻辑建模上、在构建和填充语义层上、以及在保持定义最新的持续维护工作上进行前期投入。总拥有成本(TCO)包括工具、建模和分析工程投入的时间,以及防止模型漂移所需的治理工作。要把这些成本与不这样做的代价相权衡,后者更大,却是隐性的:表现为重复的数据管道、把分析师变成人肉对账引擎,以及高管们基于没有人能够解释清楚的数字自信满满地做出决策。要用领导层的语言来陈述这个案例。每项指标只有一个可信赖的定义,正是让他们能够跨业务比较、信任仪表盘、并在没有临时救火的情况下回答监管方询问的关键。从对账痛点最严重的地方入手,把那几项指标先定义好,让省下来的时间为其余部分提供资金。
反模式与陷阱
- 直接跳到物理表设计,把今天的技术选择固化进本应比它更长久的决策中。
- 在每一个仪表盘中独立地定义同一项指标,导致没有两个数字能够一致。
- 不说明粒度,之后在营收报表中发现被重复计算的度量。
- 意外地而非通过记录在案的决策反规范化分析型表。
- 把一个分析型数据仓库规范化到每条查询都是一次没有人能理解的十二张表联结。
- 通过覆盖来处理缓变维度,导致历史报表在无声中改写了过去。
- 到处使用自然键,导致源系统的一次键变化波及整个数据仓库。
- 构建一个没有负责人的语义层,导致定义漂移、信任被侵蚀。
- 把模型当作在上线时就已完成的东西,而不是一个必须保持可演进性的有生命的资产。
成熟度模型
- 第 1 级,启动: 建模是隐性且被动应对的。表由任何需要它们的人以物理优先的方式设计。指标在每份报表中被重新定义,数字经常互相矛盾。粒度没有文档记录,没有人拥有这些定义。
- 第 2 级,发展: 一些分析型表遵循维度模式,少数关键指标有书面定义,但它们存放在一个维基页面里,且没有强制执行。命名约定存在于纸面上。实践因团队而异,对账工作仍然频繁且依赖手工。
- 第 3 级,标准化: 概念模型、逻辑模型和物理模型彼此区分并经过评审。一个语义层以有版本、有负责人的代码形式定义核心指标,且只定义一次。一致维度让团队能够安全地联结数据。粒度和缓变维度策略在整个组织范围内被记录文档并在评审中强制执行。
- 第 4 级,管理: 模型体系被对照基线进行度量。你跟踪指标定义覆盖率(由语义层提供服务的已报告指标所占比例)、当前仍在使用的重复或影子定义数量、每季度花在对账上的工时,以及在评审阶段而非生产环境中被发现的粒度和血缘缺陷的比例。定义变更通过经过评审、配有测试的拉取请求流转,新鲜度、测试通过率和漂移情况都在仪表盘上被持续监控。当一项指标出现分歧或一个维度不再保持一致时,度量机制会在董事会会议发现之前先一步暴露它。
- 第 5 级,编排: 每一项重要指标都有一个受治理的定义,被所有工具和团队共同消费,语义层与分析、实验和受监管的报告集成在一起。模型天生可演进,并被持续改进;定义在整个组织范围内被信赖;对账工作已经基本消失。随着业务变化,组织例行地弃用、重新界定和一致化新的维度,把整个模型体系作为一项自适应资产来动态调整。
讨论思路
- 选出你最重要的三项指标。今天在你的各个工具中,每一项各自存在多少种不同的定义,把它们归并为一个需要做些什么?
- 一个未被说明的粒度在哪里造成过一次真实的报告错误,被发现花了多长时间?
- 你的哪些维度应当最先在各团队之间实现一致,由谁负责拥有它们?
- 你的指标定义是保存在带评审的版本控制中,还是可以在 BI 工具内部被悄悄编辑?
- 上一次一个缓变维度在没有人察觉的情况下改写了你的历史,是什么时候,下一次你要如何捕捉到它?
- 如果你明天要更换你的数据仓库引擎,你模型的含义中有多少能够在迁移中保留下来?
关键要点
- 数据建模是在决定数据意味着什么,而这层含义比你所选择的任何存储技术都更长久。
- 按顺序分三个层级建模:先概念,再逻辑,最后物理。
- 为正确性而规范化事务型系统;为速度而有意识地反规范化分析型系统。
- 在分析场景中采用带事实表、维度表和明确粒度的维度建模。
- 构建一个语义层,让每项业务指标在任何地方都拥有一个受治理的唯一定义。
- 一致维度让独立的团队能够满怀信心地联结和比较各自的数据。
- 良好命名、记录文档、使用代理键并为定义设置版本,让模型保持可演进性。
参考资料与延伸阅读
- Ralph Kimball and Margy Ross, The Data Warehouse Toolkit: The Definitive Guide to Dimensional Modeling.
- Bill Inmon, Building the Data Warehouse.
- Dan Linstedt and Michael Olschimke, Building a Scalable Data Warehouse with Data Vault 2.0.
- Peter Chen, “The Entity-Relationship Model: Toward a Unified View of Data,” ACM Transactions on Database Systems.
- E. F. Codd, “A Relational Model of Data for Large Shared Data Banks,” Communications of the ACM.
- C. J. Date, An Introduction to Database Systems.
- Lars Rönnbäck and colleagues, writings on anchor modeling.
- DAMA International, DAMA-DMBOK: Data Management Body of Knowledge.