PDM-only 约束校验(PDM-Only Constraint Validation)· 当 FK/CHECK 只存在于模型、不在数据库里
版本:v1.0 |日期:2026-07-06 |状态:已定稿
文档定位:这是《Schema-RAG-Patterns.md》《Multi-Source-Ontology-Federation.md》的上游专题文档。前两份文档假设"表的用途与关系"是已知或可推断的;本文档回答一个更前置、更隐蔽的问题:当外键(FK)、CHECK 约束、唯一约束为了写入性能而只存在于 PowerDesigner PDM 里、并未在数据库中物化为约束时,怎么校验这些"看不见的约束"是否仍然正确?这是企业级大库(特别是为高吞吐牺牲了 DB 级约束的 OLTP/日志库)做自动化理解的必经难点。
目录
- §0 为什么"约束只在 PDM"是个被低估的难题
- §1 PDM-only 约束的四类与各自的校验难点
- §2 核心方法:三源证据交叉验证(无 DB 约束版)
- §3 FK 校验的工程化(最复杂的一类)
- §4 CHECK / 唯一约束的校验
- §5 置信度评分模型
- §6 规模与成本控制
- §7 校验后的处置:接受、软约束、修复
- §8 反模式
- §9 与已有文档的关系
- §10 总结:三个判断
- 参考资料
0. 为什么"约束只在 PDM"是个被低估的难题
很多人以为"有 PDM 就够了,约束在不在数据库里无所谓"。但只要真去做自动化数据理解,就会发现这是最棘手的一类。原因有四:
0.1 性能驱动的"约束缺失"是设计,不是疏忽
高吞吐场景(日志库、监控库、订单库高峰期)为了写入吞吐,故意不建 DB 级 FK/CHECK:FK 每次插入都要跨表校验,代价在百万 TPS 下不可接受;CHECK 也有额外开销。所以工程师把这些约束只画在 PDM 里(文档化语义),DB 里只有"裸表 + 索引"。这是有意的工程权衡,不是漏建。
后果:PDM 里写着
orders.cust_id → customers.id (FK),但数据库的information_schema里查不到这条 FK。自动化工具若只读 DB 元数据,会以为这两张表无关:这恰恰是推理出错(多跳走偏、关系漏发现)的根因。
0.2 PDM 准确度不等于约束准确度
即使 PDM 整体准确度 80-90%,约束部分的准确度往往更低。因为约束是"最容易过时"的部分:业务改了关联规则、表重构了、软外键换了指向,但 PDM 里的 FK 箭头没人改。一个常见现象是:PDM 整体看着对,但 20% 的 FK 指向已失效(指向的列已废、或关系已改)。
0.3 没有 DB 约束可对照,校验方法必须换
普通的 schema drift 检测(PDM vsinformation_schema)在这里失效:DB 里压根没这条约束,diff 出来"PDM 有、DB 没有"是预期的,不能据此判定 PDM 错。必须改用数据级和行为级证据来校验一条"看不见的约束"。
0.4 错约束比缺约束更危险
缺约束(PDM 漏标)只是少发现关系;错约束(PDM 标错)会主动误导:下游的 GraphRAG 多跳推理会沿着错的 FK 箭头走到无关表,产出"看着对实际全错"的结果。这是为什么 FK 校验必须做,且要做准。
本文核心论点:当约束只存在于 PDM 而不在 DB 时,校验的本质从"对账"(reconcile 两份显式声明)变成**“证伪”**:用数据是否服从这条约束来判断它是否还成立。一条 PDM 声明的 FK,只要数据持续违反它(引用值大量不在被引用表),它就大概率已失效。下面展开方法。
1. PDM-only 约束的四类与各自的校验难点
PDM 里可能"只在模型、不在 DB"的约束主要有四类,校验难度差异巨大:
| 约束类型 | PDM 里的形式 | 校验难度 | 核心难点 |
|---|---|---|---|
| 外键 FK | child.col → parent.pk | 最高 | 要跨表查值域包含,数据脏会干扰判断 |
| CHECK 约束 | col IN ('a','b')/col > 0/col ~ regex | 中 | 单表内验证,但要识别"业务上允许的脏值" vs “约束已失效” |
| 唯一约束 UNIQUE | UNIQUE(col_a, col_b) | 中低 | 单表 count distinct,但要处理软重复(历史数据) |
| NOT NULL | col IS NOT NULL | 低 | 单表 count null,最简单 |
本文重点在前两类(FK 与 CHECK):UNIQUE/NOT NULL 校验直白(查数据即可,如 Qualytics/Great Expectations 的 schema 校验 [10]),而 FK/CHECK 因为涉及"约束 vs 脏数据"的区分,是真正的工程难点。
1.1 FK 的特殊性:引用完整性无法靠 DB 兜底
DB 里有 FK 时,违反引用完整性的插入会被 DB 直接拒:数据天然服从约束。PDM-only FK 没有这道兜底,数据可能早就违反了(插入了指向已删客户的订单),但你不知道。所以 FK 校验必须主动跑引用完整性检查(referential integrity check),这是 Great Expectations、Dataedo、Databricks informational constraint 等工具的核心用途 [1] [2] [3] [11]。其底层依赖包含依赖检测(Inclusion Dependency, IND):判断 child 列值是否都出现在 parent 列里,Bauckmann 等给出了高效算法 [5]。
1.2 CHECK 的特殊性:违规可能是脏数据,也可能是约束变了
status IN ('active','closed')这条 CHECK,若数据里出现status='suspended',有两种可能:① 业务新增了 suspended 状态但 PDM 没更新(约束过时,该改 PDM);② 这是脏数据(约束对,数据错,该清洗)。校验工具无法自动区分这两种,必须结合业务判断或 LLM 语义推理。
2. 核心方法:三源证据交叉验证(无 DB 约束版)
配套的 PDM 校准管线用"元数据/血缘/数据"三路验证。但当约束只在 PDM 时,元数据这路基本失效(DB 元数据查不到约束),所以必须强化另外两路,并加入第四路:行为证据(实际查询怎么用的)。
PDM 声明的约束(如: child.col → parent.pk 是 FK) │ ├── 证据①:数据服从性(主动跑约束校验) │ FK: child.col 的值有多少在 parent.pk 里(引用完整性) │ CHECK: 有多少行违反规则 │ → 核心证据,违反率高则约束存疑 │ ├── 证据②:血缘行为(SQL 实际怎么 JOIN) │ SQL 日志里这条关系被 JOIN 使用的频率 │ → 从没用过 = 关系可能已废 │ ├── 证据③:LLM 语义判断 │ 列名/注释/样本 是否支持这条关系/约束合理 │ → 补语义维度 │ └── 证据④:演化历史(约束何时加的、改过没) PDM 版本历史 + 表的变更记录 → 老约束风险更高 │ ▼ 加权投票 → 置信度 高 → 采信(约束仍有效) 中 → 待审 低 → 标记失效/人工复核与配套管线的关键区别:配套管线里"元数据 diff"是第一层(全自动高置信);本文场景元数据这路失效,数据服从性证据升级为第一主力。这是"PDM-only 约束"场景的方法学核心调整。该思路与 Flatiron DATA-VALID 框架(对自动抽取数据建立分级置信与验证)[8]、Palantir 的 LLM schema matching 多源核对 [9] 同源。
3. FK 校验的工程化(最复杂的一类)
FK 是最值得展开的:它最难、最容易错、危害最大。
3.1 引用完整性检查(Referential Integrity Check)
对 PDM 声明的每条 FK,主动算"引用值有多少在被引用表里":
defcheck_referential_integrity(child_tbl,child_col,parent_tbl,parent_col,sample_ratio=0.1):"""校验 PDM 声明的 FK: child.col → parent.pk 是否仍被数据服从。"""# 采样 child 表(大表不全扫),取 FK 列的非空值fk_values=sample_query(f"SELECT{child_col}FROM{child_tbl}WHERE{child_col}IS NOT NULL",ratio=sample_ratio)# 批量查这些值在 parent 表的命中情况matched,total=batch_check_membership(fk_values,parent_tbl,parent_col)violation_rate=1-matched/totalreturn{"fk":f"{child_tbl}.{child_col}→{parent_tbl}.{parent_col}","violation_rate":violation_rate,# 核心指标"sample_size":total,"verdict":classify_violation(violation_rate),}defclassify_violation(rate):# 阈值需按业务调,以下是经验起点ifrate<0.01:return"high_confidence"# <1% 违规:约束有效(零星脏值)ifrate<0.10:return"medium"# 1-10%:可能有脏数据,约束大概率仍有效ifrate<0.50:return"suspect"# 10-50%:约束存疑(可能已失效或半失效)return"likely_invalid"# >50% 违规:约束大概率已失效阈值是核心决策点:1% / 10% / 50% 是经验起点,必须按业务调。有些域容忍高脏值(日志库引用实体常缺失),有些零容忍(财务)。阈值不能一刀切,建议按业务域分组建阈值 profile。
3.2 关键难点:区分"约束失效" vs “数据脏”
violation_rate 高时,有两种本质不同的原因,处置完全相反:
| 原因 | violation_rate 表现 | 正确处置 |
|---|---|---|
| 约束已失效(关系改了/表重构了) | 违规值有规律(如全指向某个已废弃的旧客户表) | 改 PDM(删/改这条 FK) |
| 数据脏(约束对,数据有问题) | 违规值零散、无规律 | 清洗数据,PDM 不动 |
怎么自动区分:看违规值的分布。如果违规值高度集中(如 80% 违规都指向同一个不存在的 parent id),更像"指向已废弃实体"(约束失效);如果违规值分散(各种不存在的 id 都有),更像脏数据。这个判断可以用 LLM 辅助:把违规值样本 + 列注释喂 LLM,让它判断"这像关系失效还是数据质量问题"。
3.3 采样策略(大表成本控制)
全表全列对跑 IND/FK 校验是 O(n²),大表不可行。分层采样:
defstratified_fk_check(child_tbl,child_col,parent_tbl,parent_col):# 第一遍:小样本(1%)快速筛查,识别高违规候选quick=check_referential_integrity(child_tbl,child_col,parent_tbl,parent_col,sample_ratio=0.01)ifquick.verdictin("high_confidence",):returnquick# 低违规,无需深查# 第二遍:对存疑的关系大样本(10%)或全量复核deep=check_referential_integrity(child_tbl,child_col,parent_tbl,parent_col,sample_ratio=0.10)# 第三遍(可选):极高价值/极存疑关系全量ifdeep.verdict=="suspect"andis_high_value(child_tbl):returncheck_referential_integrity(child_tbl,child_col,parent_tbl,parent_col,sample_ratio=1.0)returndeep工程要点:① 分层采样把成本集中在存疑关系上,高置信的一遍过;②时间维度采样:不同时段查(业务高峰 vs 低谷),因为高峰期可能临时数据脏;③ 校验结果要带
checked_at和sample_size,支持后续复检与置信度衰减(老结果可信度下降);④ IND 检测的扩展性在大表上是硬约束,Kruse BTW 2015 讨论了 scale-out 策略 [12]。
3.4 行为证据:用查询日志佐证 FK 是否真被用
光看数据服从性还不够。加一路行为证据:翻 SQL 查询日志,看这条 FK 关系在实际业务查询里被 JOIN 的频率。
defbehavior_evidence(child_tbl,parent_tbl,sql_log):"""从查询日志统计这条 FK 被实际 JOIN 的频率。"""joins=sql_log.find_joins_between(child_tbl,parent_tbl)return{"join_count":len(joins),"distinct_queries":len({j.query_idforjinjoins}),"verdict":"used"iflen(joins)>0else"never_used",}# never_used 的 FK:数据服从但从未被查 → 可能是"僵尸约束"(PDM 历史遗留,业务早不用)行为证据的价值:数据服从(violation_rate 低)+ 从未 JOIN = 可能是僵尸 FK:PDM 里画着,数据碰巧服从,但业务查询从不走这条路。这类 FK 留着会污染多跳推理(GraphRAG 会沿它走到无关表)。把它标"低业务价值",多跳时降权或忽略。
3.5 多列复合 FK 的特殊处理
PDM 可能声明复合外键(order_id, line_no) → (order_id, line_no)。这种校验要按列组合而非单列:
# 复合 FK:必须同时匹配所有列matched=check_membership_composite(child_rows=[(r.order_id,r.line_no)forrinsample_child],parent_tbl="order_lines",parent_cols=["order_id","line_no"])Zhang et al. (VLDB 2010) 的多列 FK 发现算法是这块的经典 [4]。对违规值"零星脏值 vs 规律失效"的精细区分,可借助条件包含依赖(CIND):Bauckmann ICDE 2012 区分"覆盖条件"(值出现时必在 parent)与"完整条件"(所有值都在 parent),能分离"关系存在但数据脏" vs “关系本身失效” [6]。候选 FK 的批量判定则可用 IND + ML 二分类的经典管线 [7]。
4. CHECK / 唯一约束的校验
4.1 CHECK 校验:违规率 + 语义判断
defcheck_check_constraint(tbl,col,rule,sample_ratio=0.1):"""校验 PDM 声明的 CHECK 约束(如 status IN ('active','closed'))。"""rows=sample_query(f"SELECT{col}FROM{tbl}",ratio=sample_ratio)violations=[rforrinrowsifnotrule.satisfies(r[col])]rate=len(violations)/max(1,len(rows))# 关键:违规值的分布(集中=约束过时;分散=脏数据)distinct_violations=Counter(r[col]forrinviolations)return{"violation_rate":rate,"violation_values":distinct_violations.most_common(10),"needs_semantic_judgment":rate>0.05,# 高违规需 LLM/人工判断原因}CHECK 校验的难点全在"违规值含义":
status='suspended'违规,是业务新增状态(改 PDM)还是脏数据(清洗)?这个判断常需 LLM 或业务专家。高频违规值喂 LLM,结合列注释判断"这像合法新值还是错误数据"。
4.2 唯一约束校验
defcheck_unique(tbl,cols,sample_ratio=0.1):"""校验 PDM 声明的 UNIQUE(col_a, col_b)。"""# 单表 count distinct vs count(*),最简单total,distinct=sample_query(f"SELECT COUNT(*) AS t, COUNT(DISTINCT ({','.join(cols)})) AS d FROM{tbl}",ratio=sample_ratio)dup_rate=1-distinct/max(1,total)# 注意:历史数据可能软重复(旧业务允许),不代表约束错return{"dup_rate":dup_rate,"verdict":classify_dup(dup_rate)}陷阱:历史数据常允许软重复(如旧版订单系统不强制唯一),dup_rate 高不代表 UNIQUE 约束错,可能只是历史遗留。要按时间分段看:近期数据 dup_rate 低、历史高 = 约束对但历史脏;全程高 = 约束可能从没生效。
5. 置信度评分模型
三源(数据/行为/语义)+ 演化证据,怎么合成一个置信度?这是"中置信进待审"的判定依据。
5.1 评分维度与权重(经验起点)
| 维度 | 权重 | 高置信信号 | 低置信信号 |
|---|---|---|---|
| 数据服从性(违规率) | 0.45 | 违规率 <1% | 违规率 >10% |
| 行为使用(JOIN 频率) | 0.25 | 频繁被查 | 从未使用 |
| LLM 语义合理性 | 0.15 | 列名/语义同源 | 语义无关 |
| 演化新鲜度(PDM 版本/表变更) | 0.15 | 近期校准过 | 老约束、表刚重构 |
defconfidence_score(data_obey,behavior,semantic,freshness):score=(0.45*data_obey# 0-1, 违规率越低越高+0.25*behavior# 0-1, 使用频率+0.15*semantic# 0-1, LLM 判定合理性+0.15*freshness)# 0-1, 新鲜度ifscore>0.85:return"high"# 自动采信ifscore>0.60:return"medium"# 待审队列return"low"# 人工复核权重不能一劳永逸:数据服从性权重最高(0.45)是因为它最客观。但某些域(日志库,引用缺失常态)数据这路噪声大,应降权、提行为权重。建议按域分权重 profile,并用人工复核结果回流校准权重(监督学习思路)。
5.2 冲突仲裁
三源常冲突(数据服从但 LLM 说语义无关)。仲裁规则:
- 数据高违规 → 一票否决(数据大量违反,无论其他路怎么说,约束都存疑)。
- 数据低违规 + 行为从未用 → 标"僵尸约束"(有效但无业务价值,多跳降权)。
- 数据低违规 + LLM 语义无关 → 进待审(可能碰巧服从,需人工确认关系真实性)。
6. 规模与成本控制
几百表 + 分表万上的库里,PDM 声明的约束可能有几千条。全量深查不可行。
6.1 优先级排序
按"价值 × 风险"排序,先查高价值高风险的约束:
defprioritize(constraints):returnsorted(constraints,key=lambdac:(value_score(c),# 核心域/高频查询表 > 长尾risk_score(c),# 老约束/表刚重构 > 新鲜约束),reverse=True)# 先校准 top 20% 高价值表的约束(覆盖 80% 业务查询路径)6.2 增量校验
不要每次全量。只校验"自上次校验后变更的部分":
- 表结构变了(DDL diff 检测)→ 重查相关约束。
- 数据大幅增长/变化 → 触发该表约束复检。
- PDM 版本更新 → 对比新旧 PDM,只查 diff 部分。
6.3 持续监控(而非一次性)
把约束校验做成周期性数据质量任务(像 Great Expectations 的 checkpoint):每周/每月跑一次采样校验,violation_rate 突然飙升 → 告警(约束可能刚开始失效)。这比一次性校验更能抓住"约束何时开始失效"。
7. 校验后的处置:接受、软约束、修复
校验出结果后,不是简单"对/错"二分,有四种处置:
| 校验结果 | 处置 | 说明 |
|---|---|---|
| 高置信有效 | 接受,入目录 | 约束仍成立,正常使用 |
| 数据服从但业务不用(僵尸) | 降权标记 | 入目录但标"低业务价值",多跳时降权或忽略 |
| 中置信存疑 | 软约束(informational) | 不强制执行,但记录供查询优化/RAG 用 [3] |
| 低置信/高违规 | 标记失效 + 人工复核 | 不入目录,或标"疑似失效",等人工确认后改 PDM |
“软约束”(informational constraint)是关键中间态:Databricks 等支持声明"informational PK/FK":不强制执行(不影响写入性能),但告诉查询优化器和下游工具"这里有个关系可用" [3]。PDM-only 约束校验后,对"数据服从但未物化"的约束,可以正式声明为 DB 的 informational constraint,让它从"PDM 里看不见"变成"系统可见但不强制":既保性能又让下游能用。
8. 反模式
反模式 1:把 PDM 约束当全真直接用
❌ PDM 里的 FK 全部当作有效关系,灌进 GraphRAG 做多跳。
后果:那 10-20% 失效/僵尸 FK 误导推理,多跳走到无关表,结果"看着对实际全错"。
正确做法:每条 PDM 约束都过校验、标置信度,低置信的不入推理图或降权。
反模式 2:因为 DB 里没约束就放弃关系发现
❌ “information_schema查不到 FK,这库没结构,没法做自动化理解。”
后果:错失 PDM 这个宝贵先验,退回从零推断,成本与准确度都差。
正确做法:PDM-only 约束正是要用数据/行为证据去验证的,不能因 DB 没物化就放弃。
反模式 3:只看违规率,不区分"约束失效 vs 数据脏"
❌ violation_rate 高就判"约束错",直接删 PDM 里的 FK。
后果:把"数据质量问题"误判成"约束失效",删了有效约束,掩盖了真正的数据脏。
正确做法:看违规值分布 + LLM/业务判断,区分两种原因,分别处置(改 PDM vs 清洗数据)。
反模式 4:全量深查所有约束
❌ 几千条 PDM 约束,每条都跑全表全列 IND 校验。
后果:成本爆炸(大表 O(n²)),周期长得不可行。
正确做法:分层采样 + 优先级排序 + 增量校验,成本集中在存疑与高价值约束。
反模式 5:校验一次就不管
❌ 做过一次校验,标记完置信度,以后不再复查。
后果:约束会持续漂移(业务变、数据长),老的校验结果过时,新失效的约束没人发现。
正确做法:周期性采样复检 + 突变告警,把约束校验作为持续的数据质量任务。
9. 与已有文档的关系
| 已有文档 | 本文关系 |
|---|---|
| 《Automated-Database-Understanding.md》 | 本文是其 §3/§4(PDM 先验融入 + 关系发现深度)的深化子专题——上游文档给自动理解的全景四层管线,本文专门处理其中"约束只在 PDM、不在 DB"这个最难的校验场景 |
| 《Schema-RAG-Patterns.md》 | 本文是其 Schema Catalog(§5)的上游校准层——catalog 里的关系字段(relations)来自本文校验后的可信约束。低置信约束不应直接进 catalog 误导路由 |
| 《Multi-Source-Ontology-Federation.md》 | 本文是其数据契约(DPROD)的关系质量保障——契约声明的 schema 关系必须经本文校验,否则契约本身不可信 |
| 《Ontology-Implementation-Patterns.md》 | 本文是模式 F(隐式本体)的前置质量门——隐式本体的列注释/关系提示若基于未校验的 PDM 约束,会把错误固化进本体 |
| 配套 PDM 校准管线 | 本文是其中"关系层校验"的深化——专门处理"约束只在 PDM"这个配套管线里元数据 diff 失效的场景 |
不重复:本文不重述配套管线的元数据 diff、血缘解析(见配套文档)。新内容:PDM-only 约束的四类与校验难点、三源证据(无 DB 约束版)、FK 校验工程化(采样/区分失效 vs 脏/行为证据/复合 FK)、置信度评分、软约束处置。
10. 总结:三个判断
判断 1:PDM-only 约束校验的本质是"证伪",不是"对账"
普通 drift 检测是两份显式声明对账(PDM vs DB)。约束只在 PDM 时,DB 那份不存在,对账无对象。校验变成用数据是否服从来证伪:持续违反的约束大概率失效。这是方法学的根本转向。
判断 2:数据服从性是第一证据,但不是唯一证据
没有 DB 约束时,数据违规率是最客观的证据(权重最高)。但它有盲区(僵尸约束:数据服从但业务不用;脏数据:违规高但约束对)。必须叠加行为证据(JOIN 频率)和语义证据(LLM 判断),三源投票才能区分"有效/僵尸/失效/脏数据"。
判断 3:软约束是性能与可信的桥梁
PDM-only 约束的本质矛盾是"要语义可信" vs “要写入性能”(所以不物化 FK)。软约束(informational constraint)破解了这个矛盾:声明关系供下游用(可信),但不强制执行(保性能)。校验后的高置信约束,应正式声明为 DB 的 informational constraint,让它从"PDM 里看不见"变成"系统可见但不强制"。
最后的话:"约束只在 PDM、不在数据库"看起来是个工程细节,实则是企业级数据理解的拦路虎。它让最常用的对账式校验失效,迫使方法转向数据证伪。但只要认清"用数据服从性 + 行为证据 + 语义判断"三源投票,配合分层采样与软约束处置,就能把那 80-90% 的 PDM 准确度持续提升到可用水平。本文是这个方向的方法学与工程框架。
参考资料
| 编号 | 来源 | 主题 | 链接 |
|---|---|---|---|
| [1] | Great Expectations | Validate Data Integrity(引用完整性/FK 校验实践) | https://docs.greatexpectations.io/docs/reference/learn/data_quality_use_cases/integrity/ |
| [2] | ChartDB | AI Foreign Key Detection(FK 检测与置信度) | https://chartdb.io/blog/foreign-keys-in-databases-importance-and-ai-detection |
| [3] | Databricks | Validate pipelines(informational PK/FK 软约束) | https://docs.databricks.com/gcp/en/transform/validate |
| [4] | VLDB (Zhang et al., 2010) | On Multi-Column Foreign Key Discovery(复合 FK 发现) | https://vldb.org/pvdb/vol3/R72.pdf |
| [5] | HPI (Bauckmann et al.) | Efficiently Detecting Inclusion Dependencies(IND 高效检测) | https://hpi.de/fileadmin/user_upload/fachgebiete/naumann/publications/PDFs/2007_bauckmann_efficiently.pdf |
| [6] | ICDE (Bauckmann et al., 2012) | Discovering Conditional Inclusion Dependencies(条件 IND:覆盖 vs 完整) | https://dl.acm.org/doi/10.1145/2396761.2398580 |
| [7] | ResearchGate (Rostin et al.) | A Machine Learning Approach to Foreign Key Discovery(IND + ML 分类) | https://www.researchgate.net/publication/221035501_A_Machine_Learning_Approach_to_Foreign_Key_Discovery |
| [8] | Flatiron Health | DATA-VALID Framework(LLM/自动抽取数据的验证方法论) | https://resources.flatiron.com/publications/ensuring-reliability-of-curated-ehr-derived-data-the-validation-of-accuracy-for-llm/ml-extracted-information-and-data-valid-framework |
| [9] | Palantir Build | Schema Matching and Data Validation Using LLMs | https://build.palantir.com/platform/ee5c0f4d-8c21-4987-be51-612973a03c99 |
| [10] | Qualytics | Data Quality Checks(schema 校验/完整性) | https://qualytics.ai/data-governance-and-quality/data-quality-checks |
| [11] | Dataedo | Testing Foreign Keys(FK 测试实践) | https://docs.dataedo.com/data-catalog/documenting/documentation-tips/testing-foreign-keys/ |
| [12] | BTW (Kruse et al., 2015) | Scaling Out the Discovery of Inclusion Dependencies(IND 扩展) | https://btw-2015.informatik.uni-hamburg.de/res/proceedings/Hauptband/Wiss/Kruse-Scaling_Out_the_Discovery_of.pdf |