尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
读时建模 vs 写时建模:问数平台如何对接多源异构业务系统
系列前三篇分别讲了「分层建模」「事件驱动协同」「指标口径中心」。这一篇再往后走一步当问数平台要回答园区出租率 能耗 工单响应这种跨系统的问题时它怎么在不改写任何一个原系统表结构的前提下把多个异构库接进来核心结论是——接入层默认走读时建模schema-on-read热数据用写时建模schema-on-write兜底两者由元数据目录统一编排。一、问题原系统不能改问题却要跨库答真实的园区/企业环境里业务数据天然分散园区自有系统智慧园区系统房源、租客、合同、账单、工单周边系统能耗 IoT 平台、门禁/停车、财务 ERP、OA、CRM问数平台数智安全问数平台的承诺是不替换原系统、只加一个问数入口。这意味着不能要求每个源系统改表结构、加字段不能把全部数据搬到一个大库里重做一遍成本、滞后、权责还要保证问出来的数可核对——能点回原表、原行。三条约束叠加把问题变成了如何在不拥有数据写权的前提下让查询引擎看懂并跨库回答这正是数据接入层Ingestion / Federation Layer要解决的。二、两种建模范式2.1 写时建模 schema-on-write传统数仓做法用 ETL 把各源数据抽出来按统一模型落进自己的库宽表 / 星型模型写入时就定好 schema。sql-- 写时建模先建统一宽表再做查询 CREATE TABLE dwd_park_rent_fact ( stat_month DATE NOT NULL, building_id VARCHAR(20) NOT NULL, rentable_area DECIMAL(12,2), rented_area DECIMAL(12,2), rent_rate DECIMAL(5,4) GENERATED ALWAYS AS (rented_area/NULLIF(rentable_area,0)), etl_batch_id BIGINT NOT NULL, etl_load_ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (stat_month, building_id) ) COMMENT 园区出租率宽表写时建模产物;优点查询快、口径稳、历史快照自然留存。缺点每接一个新源或新口径都要改 ETL、改表开发重、上线慢、对源系统有搬运依赖。2.2 读时建模 schema-on-read保留源表不动在元数据层定义虚拟模型查询时再实时映射到源字段。schema 不在写入时定而在读取时定。yaml# virtual_model: 出租率读时建模定义在元数据层不落物理表 model: park_rent_rate source: smart_park.biz_contract # 智慧园区系统只读库 dimensions: - {name: stat_month, expr: DATE_FORMAT(contract_start,%Y-%m)} - {name: building_id, expr: building_id} measures: - {name: rentable_area, expr: SUM(area)} - {name: rented_area, expr: SUM(CASE WHEN status生效 THEN area ELSE 0 END)} filters: - contract_start CURRENT_DATE - deleted 0 security: row_level: building_id IN (:visible_buildings) # 权限推下优点不动源表、按需扩展、上线轻。新源接进来只是加一条 catalog 记录 一份映射不碰 ETL。缺点跨库 join、下推性能要靠引擎兜底源字段类型/质量不一致要在映射层显式处理。结论问数平台以读时建模为主接得快、不碰源对高频热问题用写时建模预计算答得快、稳。二者不是二选一而是分层共存。三、接入层架构源系统 (只读账号) │ ┌─────────── 接入连接器 ───────────┐ │ │ MySQL只读 │ PG-CDC │ REST轮询 │ 文件│ └─└───────────┬─────────────────────┘ ▼ 元数据目录 catalog (source_connector / catalog_table / catalog_column) ▼ 虚拟模型 virtual_model model_mapping (读时建模) ▼ 问数引擎 (NL→SQL→联邦执行→口径校验→结果) ▼ 写时建模兜底热数据预计算宽表materialized设计原则连接只读每个源系统只给一个只读账号问数平台永远不写源库元数据统一哪些库、哪些表、哪些列可被问全部登记在 catalog不是散落在代码里虚拟模型可叠加同一份源字段可以按不同口径定义多个虚拟模型招商口径、运营口径、财务口径互不干扰热数据预计算被高频问到的模型异步落一张物化宽表查询走宽表源库零压力。四、元数据目录 DDL把接入与建模当成一等公民存起来sql-- 连接器每个源系统一条记录 CREATE TABLE source_connector ( connector_id VARCHAR(32) PRIMARY KEY, connector_name VARCHAR(64) NOT NULL, db_type VARCHAR(16) NOT NULL COMMENT mysql|postgres|oracle|rest|file, conn_mode VARCHAR(16) NOT NULL COMMENT readonly|cdc|poll, host VARCHAR(128), port INT, db_name VARCHAR(64), readonly_account VARCHAR(64) NOT NULL COMMENT 专用只读账号, encrypt_secret VARCHAR(256) NOT NULL COMMENT 凭据加密存储, enabled TINYINT NOT NULL DEFAULT 1, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) COMMENT 源系统连接器注册表; -- 目录表登记可被问的表 CREATE TABLE catalog_table ( table_id VARCHAR(40) PRIMARY KEY, connector_id VARCHAR(32) NOT NULL, schema_name VARCHAR(64) NOT NULL, table_name VARCHAR(64) NOT NULL, biz_label VARCHAR(64) NOT NULL COMMENT 业务含义如「租赁合同」, row_count_est BIGINT, last_sync_ts TIMESTAMP, UNIQUE KEY uk_conn_tbl (connector_id, schema_name, table_name) ) COMMENT 可被问的表目录; -- 目录列登记可被问的列与类型 CREATE TABLE catalog_column ( column_id VARCHAR(48) PRIMARY KEY, table_id VARCHAR(40) NOT NULL, column_name VARCHAR(64) NOT NULL, data_type VARCHAR(32) NOT NULL COMMENT 统一后的逻辑类型, biz_label VARCHAR(64), is_pii TINYINT NOT NULL DEFAULT 0 COMMENT 是否敏感用于脱敏, UNIQUE KEY uk_tbl_col (table_id, column_name) ) COMMENT 可被问的列目录; -- 虚拟模型读时建模的定义本身 CREATE TABLE virtual_model ( model_id VARCHAR(40) PRIMARY KEY, model_name VARCHAR(64) NOT NULL, definition MEDIUMTEXT NOT NULL COMMENT YAML/JSON 形式的维度与度量定义, owner VARCHAR(64), version INT NOT NULL DEFAULT 1, effective_from DATE NOT NULL, effective_to DATE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) COMMENT 读时建模虚拟模型; -- 模型映射虚拟字段到源表列的具体映射 CREATE TABLE model_mapping ( mapping_id VARCHAR(48) PRIMARY KEY, model_id VARCHAR(40) NOT NULL, table_id VARCHAR(40) NOT NULL, field_name VARCHAR(64) NOT NULL COMMENT 虚拟字段名, source_expr VARCHAR(512) NOT NULL COMMENT 映射到的源表达式, agg VARCHAR(16) COMMENT sum|count|avg|none ) COMMENT 虚拟字段→源列映射;五、连接器配置示例不同源用不同接入方式配置即代码yamlconnectors: # 智慧园区系统MySQL 只读直连 - id: smart_park type: mysql mode: readonly host: 10.20.3.11 port: 3306 db: park_biz account: qa_readonly # 专用只读账号无写权限 secret_ref: vault://park/qa_ro # 能耗 IoTPostgreSQL用 CDC 捕获变更 - id: iot_energy type: postgres mode: cdc host: 10.20.3.21 port: 5432 db: energy slot: park_energy_slot # 逻辑复制槽避免断点丢失 account: qa_readonly secret_ref: vault://energy/qa_ro # 门禁/停车REST 轮询无直连条件时 - id: access_gate type: rest mode: poll endpoint: https://gate.internal/api/v1/records poll_cron: */15 * * * * # 每15分钟增量拉取 token_ref: vault://gate/qa_token # 财务 ERP文件落地后解析 - id: finance_erp type: file mode: poll path: /data/inbox/finance/ format: xlsx不同源用不同modereadonly直连、cdc逻辑复制、poll轮询/文件。无论哪种账号都是源系统侧的专用只读账号问数平台对源库零写权。六、只读与权限推下只看该看的必须在查询执行时推下到源而不是把全量拉回来再过滤。sql-- 行级权限问数引擎在生成 SQL 时自动注入 tenant/building 可见范围 SELECT building_id, SUM(area) AS rentable_area, SUM(CASE WHEN status生效 THEN area ELSE 0 END) AS rented_area FROM smart_park.biz_contract WHERE contract_start CURRENT_DATE AND deleted 0 AND building_id IN ( -- ↓ 权限推下自动注入 SELECT building_id FROM dim_user_visible_building WHERE user_id :current_user_id ) GROUP BY building_id;要点只读账号 行级视图/策略源库侧先把超范围数据挡住问数引擎按当前用户的可视范围把IN (...)注入到每一条下推 SQL敏感列is_pii1在 catalog 层标记返回前做脱敏如手机号中间四位打码查询留痕谁、什么时间、问了什么、命中哪些源表全部落审计表见第三篇。七、跨库聚合的查询路由跨系统问题B 栋出租率 vs 同楼宇能耗需要把查询拆成子查询下推到各自源库再在引擎层汇聚用户问: B栋本季度出租率和单位面积能耗是多少? ├─ 子查询1 下推 smart_park (只读) : 出租率相关字段 ├─ 子查询2 下推 iot_energy (cdc) : 能耗读数 └─ 引擎层 JOIN on building_id 时间对齐 单位换算 返回: 结论 图表 明细(两源各自来源) 来源标注路由策略能下推的尽量下推过滤、聚合在源库做减少传输跨库 join 不强行下推改为各源取明细→引擎内存汇聚避免源库间暴露连接类型/单位不一致在 virtual_model 的source_expr里统一如 kWh 与 Wh 在映射层换算。八、增量同步 CDC对变化频繁又要求近实时的源能耗、门禁用 CDC 而非全量轮询yamlcdc: connector: iot_energy capture: # 捕获的变更表 - table: energy.meter_reading pk: [meter_id, read_ts] track_columns: [kwh, quality] buffer: # 变更缓冲断点可恢复 type: kafka topic: park_energy_cdc offset_store: /data/cdc/offset_energy apply_to: # 应用到虚拟模型 - virtual_model: building_energy_rate dedup_key: [meter_id, read_ts] late_window: 24h # 迟到数据窗口CDC 要点用逻辑复制槽 / binlog拿变更断点offset持久化重启不丢写入缓冲Kafka做削峰与重放按主键去重避免重复计设置迟到窗口乱序数据仍能进正确区间。九、实时 vs 批量 / 读时 vs 写时 权衡维度读时建模(默认)写时建模(兜底)接入速度快加 catalog映射慢建 ETL宽表对源系统侵入无只读无但要落自己的库查询性能依赖下推中等预计算快口径变更成本改 YAML 即可改 ETL重算适用长尾问题、新源、低频高频热问题、固定报表一致性近实时CDC/轮询快照一致工程上90% 的问法走读时建模10% 的高频热问题用写时建模物化二者通过同一个 virtual_model 名称路由对上层问数完全透明。十、一个落地示例假设园区负责人问B 栋本季度出租率和去年同期比怎么样这条问题在接入层是这样被接住的不问源库改结构biz_contract表本来就有building_id / area / status / contract_start读时建模直接映射源系统零改动口径统一出租率 生效面积 / 可租面积定义一次招商/运营/财务问同一个数权限推下当前用户只看 B 栋building_id IN (:visible)自动注入看不到其他楼同比可比virtual_model带version与effective_from去年和今年的口径若变过历史口径保留同比不会错配结果可核对返回的图表旁附明细每条都能点回biz_contract的具体行——这正是问数平台敢用的底线。若这条问题每天被问上百次引擎会把该虚拟模型物化成一张dwd_park_rent_fact宽表写时建模兜底后续查询走宽表源库零压力上层问法不变。十一、工程踩坑表#坑现象对策1源表改名/加前缀catalog 映射失效问不出catalog 与源解耦改名走映射不改问法2类型不一致金额 varchar 与 decimal 相加报错在source_expr显式 cast 统一3时区漂移跨系统按时间对齐错位虚拟模型统一 UTC展示层转本地4权限越界看到不该看的楼栋行级IN(:visible)强制注入 源库视图5CDC 断点丢失重启用全量数据暴涨offset 持久化 逻辑复制槽6NULL 语义空置面积 null 被当 0口径层显式COALESCE规则7编码乱码中文列名/值乱码连接层统一 UTF-8源库校对8跨库 join 性能引擎内存汇聚 OOM限制返回行数 分页 下推聚合9重复主键CDC 重放致重复计按 pkts 去重幂等写入10无人维护 catalog接完没人管慢慢失准catalog 变更走评审配负责人字段十二、关于本文涉及的两套系统本文的接入层、读时建模、元数据目录、权限推下都是数智安全问数平台鲁联数智的工程实现细节——它坚持不替换原业务系统、只加一个问数入口。而它要读的那个原系统正是智慧园区系统房源、租客、合同、账单、工单这些业务数据由智慧园区系统发生并沉淀问数平台在其之上看懂。两者分工一句概括智慧园区系统负责有得查问数平台负责问得清。
RELATED

相关推荐

智慧农业数据采集从零到一:MQTT 接入边缘网关完整教程(附实测可运行代码)

智慧农业数据采集从零到一:MQTT 接入边缘网关完整教程(附实测可运行代码)

智慧农业数据采集从零到一:MQTT 接入边缘网关完整教程(附实测可运行代码) 前言 做农业物联网项目,第一个卡点几乎永远是同一个:现场传感器采集到的数据,怎么稳定地送进你的数据库。 本文用一个完整示例走通…

📅 2026/10/23 9:17:19
RocketMQ 集群特性

RocketMQ 集群特性

摘要:本文重点梳理 Dledger 文件一致性协议(含 Raft 原理与 RocketMQ 实现)、主从节点切换的高可用集群、BrokerContainer 容器式运行机制。 一、Dledger 文件一致性协议 1. Dledger 高可用集群下的消息一致性问题 RocketMQ 提供两种集群机…

📅 2026/10/23 9:17:19
基于微信小程序的ACG手办商店系统(毕设源码+文档)

基于微信小程序的ACG手办商店系统(毕设源码+文档)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

📅 2026/10/23 9:17:19
MORE NEWS

更多资讯

📰

FGO-py 实战指南:自动爬塔 + 自动每周任务,睡前挂上它一晚刷完

FGO-py 实战指南:自动爬塔 自动每周任务,睡前挂上它一晚刷完 【免费下载链接】FGO-py 自动爬塔! 自动每周任务! 全自动免配置跨平台的Fate/Grand Order助手.启动脚本,上床睡觉,养肝护发,满加成圣诞了解一下? 项目地址: https://gitcode.com/GitHub_T…

📰

Oh My Zsh 插件文档完全指南:从安装到自定义的 10 分钟上手路径

Oh My Zsh 插件文档完全指南:从安装到自定义的 10 分钟上手路径 【免费下载链接】ohmyzsh 🙃 A delightful community-driven (with 2,500 contributors) framework for managing your zsh configuration. Includes 300 optional plugins (rails, git, m…

📰

如何先写和弦再填旋律:YuE2 Studio 和弦床(Chord Bed)工作流全解析

【免费下载链接】YuE2-Studio Local AI song generator with an editable score — YuE2 on your GPU: full songs with vocals, sheet music, covers, exact replay. Native Windows app, no Python, installer with auto-update. 项目地址: https://gitcode.com/g…

📰

把微信聊天记录永久保存:WeChatMsg 五个目标跑通

把微信聊天记录永久保存:WeChatMsg 五个目标跑通 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatMsg …

📰

FreeRDP命令行实战:Windows远程桌面批量连接与参数配置指南

上周有个做运维的朋友甩过来一句抱怨:手头二十多台 Windows 机器的远程会话,每天要一台台点开系统自带的远程桌面连接、填地址、填账号、点确定,一天下来手指头都酸了,更别提还要在几个会话之间来回切着看日志。他问我有没有办法把…

📰

Linux安装微信的真相:四大路径实测与决策指南

1. 为什么“在Linux系统中安装微信”是个高频却总被误答的问题 “如何在Linux系统中安装微信”——这个搜索词每天在各大技术社区、问答平台和新手群组里出现数百次。它看起来简单,但背后藏着一个典型的认知断层:多数提问者真正想问的,不是“…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬