3. 临床数据模型与数据集市建模

临床专题数据集市与通用业务数据集市最大的区别在于:临床数据天然带有“事件—时间—主体—观察值”四重结构,且同一患者在不同时间点会反复产生同类记录。因此,建模时不能只考虑“怎么把表连起来”,而要先回答“这个专题要回答什么临床问题、按什么粒度聚合、哪些维度必须保留可追溯性”。维度建模正是为这类分析型场景服务的建模方法,它把数据组织成“事实表 + 维度表”的组合,让指标计算路径清晰、查询性能可控。

一、维度建模在临床专题中的基本形态

维度建模的核心是确定事实表粒度。以“患者检验专题”为例,最细粒度通常是一次检验项目结果,即“患者 + 就诊 + 检验申请 + 检验项目 + 报告时间”唯一确定一行。事实表中存放可加或半可加的度量,如检验结果值、参考区间上下限、异常标志;维度表则存放描述性属性,如患者维度(性别、年龄、出生日期)、时间维度(日期、周、月、季度)、机构维度(院区、科室)、项目维度(检验项目编码、名称、标本类型、单位)。

临床维度有一个特殊要求:缓慢变化维必须可追溯。例如患者科室会随就诊变化,检验项目参考区间会随仪器或标准更新。若直接覆盖旧值,历史指标会失真。常用做法是采用类型 2 缓慢变化维,为维度行增加生效时间、失效时间和当前标志,使“当时的事实”能关联“当时的维度”。

二、宽表设计:把常用路径固化下来

宽表不是“把所有字段堆在一起”,而是围绕一个明确的分析主题和查询模式,把事实与高频维度预先关联。临床专题中常见的宽表是“患者检验结果宽表”,其字段可包括:患者标识、就诊号、科室、检验项目、结果值、单位、参考区间、异常等级、报告时间、标本采集时间。宽表的价值在于减少多表连接,让指标平台在计算“某科室某月异常检验发生率”时只需扫描一张表。

但宽表也有代价:冗余存储、更新链路变长、维度变更时需要重刷历史分区。因此建议按“专题 + 时间分区”组织宽表,例如按报告日期做日分区,并保留事实表作为明细底座。宽表是服务层,不是唯一数据源。

三、星型与雪花模型的选型

星型模型以事实表为中心,维度表只做一层展开,结构简单、连接少、查询快,适合指标平台中高频、固定的分析路径。雪花模型则把维度进一步规范化,例如把“科室”拆成科室、病区、院区多层表,减少冗余但增加连接。临床专题中,如果维度层级稳定、查询以聚合为主,优先星型;如果机构、项目、诊断等维度存在多级编码体系且需要独立维护,可在局部采用雪花。

选型时可参考三个判断点:查询频率(高频走星型)、维度变更频率(频繁变更且需追溯时,维度独立成表更稳)、团队维护成本(雪花模型对 ETL 和血缘要求更高)。在同一个数据集市中,星型与雪花并非互斥,可以主星型、局部雪花。

临床检验专题:事实表 + 维度表建模选型 粒度:患者 + 就诊 + 检验申请 + 检验项目 + 报告时间 事实表:检验结果事实 结果值 · 参考区间 · 异常标志 报告时间 · 采集时间 · 就诊号 可加度量 + 外键 患者维度 性别 · 年龄 · 出生日期 类型2:生效/失效时间 时间维度 日 · 周 · 月 · 季度 工作日/节假日标志 检验项目维度 项目编码 · 名称 · 单位 标本类型 · 参考区间版本 机构维度 院区 · 科室 · 病区 雪花:层级独立维护 诊断维度 ICD 编码 · 诊断名称 诊断类型 · 主/次诊断 服务层:检验结果宽表 按报告日期分区 · 预关联高频维度 面向指标平台直接聚合 星型:事实表直连维度;雪花:机构/诊断等维度按层级独立成表,局部使用

四、落地过程:从临床问题到可查询模型

假设要建设“住院患者血糖管理专题”,目标是回答“各科室住院患者血糖异常率、复查率、危急值响应时长”。落地可按以下路径推进。

第一步,定义指标与粒度。血糖异常率 = 异常血糖结果数 / 血糖结果总数;复查率 = 同一患者 24 小时内再次检测血糖的就诊次数占比;危急值响应时长 = 危急值报告时间到临床确认时间的中位数。粒度统一到“患者 + 就诊 + 检验项目 + 报告时间”。

第二步,确定事实与维度。事实表存放血糖结果值、单位、异常等级、危急值标志、报告时间、确认时间;维度包括患者、时间、科室、检验项目、危急值等级。科室维度若需要院区—科室—病区三级,可拆成雪花结构,但对外仍以科室维度视图暴露。

第三步,设计宽表分区与更新。宽表按报告日期做日分区,每日增量刷新最近 3 天分区以吸收迟到数据;维度变更通过类型 2 缓慢变化维保留历史。指标平台查询时优先命中宽表,明细追溯再回退到事实表。

-- 示例:检验结果事实表(简化)
CREATE TABLE fact_lab_result (
  patient_id      BIGINT,
  visit_id        BIGINT,
  item_id         INT,
  dept_id         INT,
  report_time     TIMESTAMP,
  result_value    DECIMAL(12,4),
  abnormal_flag   VARCHAR(8),
  critical_flag   VARCHAR(4),
  confirm_time    TIMESTAMP
) PARTITION BY RANGE (report_time);

-- 示例:检验项目维度(类型2缓慢变化维)
CREATE TABLE dim_lab_item (
  item_sk         BIGINT,
  item_id         INT,
  item_name       VARCHAR(128),
  unit            VARCHAR(32),
  ref_low         DECIMAL(12,4),
  ref_high        DECIMAL(12,4),
  effective_from  DATE,
  effective_to    DATE,
  is_current      BOOLEAN
);

第四步,验证与判断。建模完成后,用三类检查确认可用性:一是粒度唯一性检查,确认事实表主键组合无重复;二是维度追溯检查,随机抽取历史指标,确认其关联的是当时生效的维度版本;三是性能检查,对“科室 + 月 + 异常率”查询,宽表方案应显著低于直接多表连接。若发现指标口径与临床统计不一致,优先回查维度版本和事实粒度,而不是先改 SQL。

临床专题建模的常见误区:把“患者”当成唯一粒度,忽略就诊和报告时间,导致同一患者多次检验被错误合并;或把参考区间直接写死在事实表,仪器或标准更新后历史结果无法解释。建议参考区间随项目维度版本管理,事实表只存结果值与版本外键。

总体而言,临床专题的维度建模应坚持“先定粒度、再定维度、后定宽表”的顺序。星型模型作为默认服务形态,雪花模型用于维度层级复杂且需独立维护的局部场景;宽表作为指标平台的高频服务层,事实表作为可追溯底座。三者配合,才能在临床专题中同时满足查询效率、口径一致与历史可追溯。