数据保险库模型要求数据仓库对关系和数据存储的看法发生根本转变。与为读取优化而预连接数据的星型模式不同,数据保险库优化了写入的灵活性和可审计性。正在为电子商务平台构建一个原始数据保险库。该系统必须从客户关系管理系统(客户数据)、企业资源规划系统(订单处理)和产品信息管理系统摄取数据。目标是构建一个支持高速数据摄取并允许源结构演变而不破坏下游数据仓库的架构。我们将着重介绍三个核心实体:中心表(业务键)、链接表(关系)和卫星表(上下文/属性)。定义架构在大规模并行处理(MPP)环境(如Snowflake或BigQuery)中,我们避免为代理键使用序列或自增整数,因为它们需要一个中央协调点,这在并行加载期间会成为瓶颈。相反,数据保险库2.0依赖于业务键的加密哈希(MD5或SHA-256)。这使得在分布式节点上可以进行确定性键生成,无需查找现有记录。以下图表概述了我们将实现的关系结构。请注意业务键如何隔离在中心表中,而时间上下文则存在于卫星表中。digraph G { rankdir=TB; node [shape=box, style=filled, fontname="Arial", fontsize=10]; edge [fontname="Arial", fontsize=8, color="#868e96"]; /* 中心表 - 蓝色 */ subgraph cluster_hubs { label="中心表(业务键)"; style=dashed; color="#adb5bd"; H_CUST [label="HUB_CUSTOMER\n(邮箱/客户ID)", fillcolor="#a5d8ff", color="#1c7ed6"]; H_ORD [label="HUB_ORDER\n(订单号)", fillcolor="#a5d8ff", color="#1c7ed6"]; H_PROD [label="HUB_PRODUCT\n(SKU)", fillcolor="#a5d8ff", color="#1c7ed6"]; } /* 链接表 - 紫罗兰色 */ subgraph cluster_links { label="链接表(事务/关联)"; style=dashed; color="#adb5bd"; L_ORD_CUST [label="LINK_ORDER_CUSTOMER", fillcolor="#d0bfff", color="#7048e8"]; L_ORD_LINE [label="LINK_ORDER_LINE", fillcolor="#d0bfff", color="#7048e8"]; } /* 卫星表 - 青绿色 */ subgraph cluster_sats { label="卫星表(上下文与历史)"; style=dashed; color="#adb5bd"; S_CUST_CRM [label="SAT_CUST_CRM\n(姓名, 地址)", fillcolor="#96f2d7", color="#0ca678"]; S_ORD_DTL [label="SAT_ORDER_DETAILS\n(状态, 日期)", fillcolor="#96f2d7", color="#0ca678"]; } /* 连接 */ H_CUST -> L_ORD_CUST; H_ORD -> L_ORD_CUST; H_ORD -> L_ORD_LINE; H_PROD -> L_ORD_LINE; H_CUST -> S_CUST_CRM [style=dotted, label="描述性"]; H_ORD -> S_ORD_DTL [style=dotted, label="描述性"]; }该图将结构组件(中心表和链接表)与描述性组件(卫星表)分开。中心表连接到链接表以构成骨架,而卫星表则附加到中心表或链接表以提供详细信息。实现中心表中心表是业务对象的入口点。它仅包含哈希键、加载日期、记录来源和原始业务键。此表很少更改。对于我们的客户实体,业务键是 Customer_ID。我们通过对修剪后、大写的业务键进行哈希处理来生成 Hub_Customer_HK(哈希键)。$$H_{键} = SHA256(UPPER(TRIM(业务键)))$$我们选择SHA-256是因为其低冲突概率,这在处理TB级数据时是必要的。HUB_CUSTOMER 的 SQL 实现:CREATE TABLE HUB_CUSTOMER ( HUB_CUSTOMER_HK BINARY(32) NOT NULL, -- 主键 CUSTOMER_ID VARCHAR(100) NOT NULL, -- 业务标识符 LOAD_DT TIMESTAMP_NTZ NOT NULL, RECORD_SOURCE VARCHAR(50) NOT NULL, CONSTRAINT PK_HUB_CUSTOMER PRIMARY KEY (HUB_CUSTOMER_HK) );加载此表时,您需要使用暂存区域中的 DISTINCT 查询。因为哈希是确定性的,您可以执行反连接(LEFT JOIN ... WHERE target.HK IS NULL)来只插入新的业务键。实现链接表链接表代表关联或事务。在我们的场景中,一个订单将客户与一个事务关联起来。LINK_ORDER_CUSTOMER 表解决了 HUB_ORDER 和 HUB_CUSTOMER 之间的多对多或一对多关系。链接表包含其自身的哈希键、所引用中心表的哈希键以及审计元数据。LINK_ORDER_CUSTOMER 的 SQL 实现:CREATE TABLE LINK_ORDER_CUSTOMER ( LNK_ORD_CUST_HK BINARY(32) NOT NULL, HUB_ORDER_HK BINARY(32) NOT NULL, HUB_CUSTOMER_HK BINARY(32) NOT NULL, LOAD_DT TIMESTAMP_NTZ NOT NULL, RECORD_SOURCE VARCHAR(50) NOT NULL, CONSTRAINT PK_LNK_ORD_CUST PRIMARY KEY (LNK_ORD_CUST_HK), CONSTRAINT FK_LNK_ORD FOREIGN KEY (HUB_ORDER_HK) REFERENCES HUB_ORDER (HUB_ORDER_HK), CONSTRAINT FK_LNK_CUST FOREIGN KEY (HUB_CUSTOMER_HK) REFERENCES HUB_CUSTOMER (HUB_CUSTOMER_HK) );要生成 LNK_ORD_CUST_HK,您需要连接参与中心表的业务键(以排序顺序确保一致性),并对结果进行哈希处理。$$H_{链接} = SHA256(Sort(键_{订单}, 键_{客户}))$$实现卫星表卫星表存储数据随时间变化的状态。它们是唯一存储可变属性(如客户地址或订单状态)的地方。卫星表必须有一个父级(通常是中心表),并使用父级的哈希键作为其主标识符,与加载日期结合使用。为了在大规模并行处理系统(MPP)中高效地检测变化,我们计算一个 HashDiff。这是行中所有描述性列的哈希值。在加载过程中,我们将传入的 HashDiff 与目标卫星表中最新的 HashDiff 进行比较。如果它们不同,则插入新行。这消除了昂贵的逐列比较。SAT_CUSTOMER_CRM 的 SQL 实现:CREATE TABLE SAT_CUSTOMER_CRM ( HUB_CUSTOMER_HK BINARY(32) NOT NULL, LOAD_DT TIMESTAMP_NTZ NOT NULL, HASH_DIFF BINARY(32) NOT NULL, -- 用于变更检测 FIRST_NAME VARCHAR(100), LAST_NAME VARCHAR(100), EMAIL VARCHAR(255), ADDRESS_JSON VARIANT, -- 存储半结构化地址数据 RECORD_SOURCE VARCHAR(50) NOT NULL, CONSTRAINT PK_SAT_CUST PRIMARY KEY (HUB_CUSTOMER_HK, LOAD_DT), CONSTRAINT FK_SAT_HUB FOREIGN KEY (HUB_CUSTOMER_HK) REFERENCES HUB_CUSTOMER (HUB_CUSTOMER_HK) );HashDiff 的计算HASH_DIFF 确保我们只存储实际的变化。此公式适用于所有描述性列:$$H_{差异} = SHA256(COALESCE(列_1, '') || '|' || COALESCE(列_2, '') || ...)$$我们使用分隔符(如 |)并处理 NULL 值,以确保 NULL + A 与 A + NULL 的处理方式不同。加载模式与并行处理我们刚刚实现的这个设计实现了高度并行。暂存: 原始数据进入暂存表。哈希生成: 我们在暂存表之上的视图中计算所有哈希键和 Hash Diffs。中心表/链接表加载: 我们并行加载中心表和链接表。由于链接表仅依赖于中心表键(我们在暂存阶段生成),技术上我们无需等待中心表加载完成即可准备链接数据,尽管数据库中的引用完整性约束可能要求中心表首先提交。卫星表加载: 卫星表通过比较暂存 HashDiff 与当前卫星 HashDiff 来加载。这种“仅插入”架构创建了完整的审计追踪。我们从不更新行。要获取客户的当前状态,您需要查询卫星表以获取特定 HUB_CUSTOMER_HK 的最大 LOAD_DT 所在的行。可视化存储影响在列式存储系统中,与宽表相比,这种分解(范式化)可能显得过多。然而,大规模并行处理系统会单独压缩列。卫星表中哈希键的重复压缩效果非常好(游程编码),并且分离避免了锁定。以下图表显示了成熟数据保险库中常见的存储分布。卫星表由于历史追踪而占用大部分存储空间,而中心表和链接表则保持为轻量级索引结构。{"layout": {"title": {"text": "数据保险库中常见的存储分布", "font": {"size": 16}}, "showlegend": true, "legend": {"orientation": "h", "y": -0.1}, "margin": {"t": 40, "b": 20, "l": 40, "r": 40}, "height": 350}, "data": [{"values": [15, 25, 60], "labels": ["中心表(键)", "链接表(关系)", "卫星表(历史与属性)"], "type": "pie", "marker": {"colors": ["#1c7ed6", "#7048e8", "#0ca678"]}, "textinfo": "label+percent", "hole": 0.4}]}卫星表不可避免地会变得最大,因为它们保留了属性变化的完整历史记录。中心表和链接表一旦核心业务实体和关系建立,就会稳定下来。通过实施这种结构,您可以确保,如果客户关系管理系统向客户资料添加新字段,您只需向卫星表添加一列(或创建一个新的卫星表),而无需重建中心表或链接表。这种适应性是数据保险库在PB级数据仓库中的主要工程优势。