标签 SQL 下的文章

本文首发于 Aloudata 官方技术博客:《指标平台选型对比:NoETL 语义编织 vs 传统 ETL/ELT,如何破解数据分析不可能三角?》转载请注明出处。

摘要:本文深入对比了传统 ETL/ELT 模式与 Aloudata CAN NoETL 语义编织平台在数据工程领域的核心差异。通过剖析“数据分析不可能三角”的根源,并从架构、开发、治理、成本四个维度进行技术对比,为数据架构师和决策者提供清晰的指标平台选型框架,旨在解决指标口径混乱、响应迟缓与成本高企的痛点。

一、决策背景:为何传统 ETL/ELT 模式陷入“数据分析不可能三角”?

在 AI 时代,海量、灵活的分析需求与依赖人工预计算物理宽表的传统数据供给模式之间,矛盾日益尖锐。企业数据团队普遍陷入一个痛苦的“不可能三角”:在“业务灵活性”、“指标口径一致性”和“性能成本”三者间,只能艰难取舍,难以兼顾。

“指标口径统一说简单真不简单……财务部和销售部都在用‘收入’这个词,但你问问他们怎么算‘收入’——一个是‘含税’,一个是‘不含税’……老板看到两个部门的‘收入’差了几十万,脸色有多精彩吗?” —— 来源:FineBI 技术社区, 2025

痛点表现具体如下:

  1. 口径混乱,数据打架:指标逻辑硬编码在分散的 ETL 脚本和物理宽表中,导致“同名不同义”。例如,财务与运营的“GMV”定义不同,管理层决策无所适从。
  2. 响应迟缓,敏捷缺失:一个新分析需求,从业务提出到数据团队排期、开发(ODS→DWD→DWS→ADS)、测试、上线,往往需要数周甚至数月。业务创新被冗长的开发链路拖累。
  3. 分析固化,下钻困难:分析路径被预建的物理宽表(ADS 层)固化。若业务想从“按省份看销售额”下钻到“按城市看”,而宽表未预先聚合城市粒度,则无法实现,灵活性极差。
  4. 成本高企,资源浪费:为保障报表查询性能,数据工程师不得不预建大量汇总宽表。相同明细数据被反复加工、存储,形成巨大的存储冗余与计算浪费,ADS 层日益臃肿。

根因剖析:这一切的根源在于传统“物理宽表驱动”的范式。业务需求必须翻译为具体的物理表结构变更,通过人工编写 ETL/SQL 来实现。这导致了漫长的开发链路、业务与技术的沟通鸿沟,以及任何变更都牵一发而动全身的维护复杂性。

引入“不可能三角”:传统模式迫使企业在三角中做出选择:要灵活分析(多建宽表)就会推高成本和加剧口径混乱;要保证口径一致和低成本(少建宽表)就会牺牲查询性能和业务灵活性。这个结构性矛盾,是当前企业数据价值释放的核心瓶颈。

二、核心差异:从“物理宽表驱动”到“语义模型驱动”的范式重构

要破解“不可能三角”,必须进行范式层面的革新。Aloudata CAN 的本质是基于 NoETL 语义编织的动态计算引擎,其核心是通过将业务语义与物理存储解耦,从根本上颠覆了传统以物理宽表为核心的指标生产模式。

范式要素传统模式 (物理宽表驱动)Aloudata CAN (语义模型驱动)
核心对象物理表(DWS/ADS 宽表)语义模型(虚拟业务事实网络)
指标定义硬编码在 ETL 脚本中声明式配置(基础度量、业务限定、统计周期、衍生计算)
开发动作编写 SQL/代码,物理建表零代码配置,系统自动生成 & 优化 SQL
治理时机事后人工核对与文档管理事前自动判重,定义即治理
架构特征烟囱式,为报表建表平台化,一处定义,处处服务

Aloudata CAN 的工作机制:

  1. 统一语义层:在干净的 DWD 明细数据层之上,通过声明式方式配置业务实体间的逻辑关联,构建一个“虚拟业务事实网络”。无需预先进行物理打宽。
  2. 定义即开发:业务人员或数据工程师通过界面,像搭积木一样配置指标的四大语义要素(如“近 30 天”、“成功支付的”、“日均交易金额”),平台自动生成最优执行 SQL,实现零代码开发。
  3. 定义即治理:在定义指标时,系统自动进行全局判重和一致性校验,确保同一个业务概念在全公司只有唯一、权威的定义,从源头杜绝口径不一。

范式结论:这场变革是从“为特定报表去建物理表”的被动、烟囱式开发,转向“基于统一的语义模型按需计算”的主动、敏捷响应。

三、四维深度对比:技术实现、业务效能与总拥有成本

下面我们从四个关键维度,系统化对比两种技术路径带来的截然不同的业务结果。

综合对比表

对比维度传统 ETL/ELT 模式Aloudata CAN NoETL 语义编织对业务的影响
核心架构依赖预计算的物理宽表(DWS/ADS层)统一语义层,直接基于 DWD 明细构建虚拟业务网络摆脱“为报表建表”的束缚,支持任意维度下钻与灵活分析
开发模式手工编写、调试 ETL/SQL 脚本,流程冗长定义即开发:配置化声明指标,系统自动生成优化 SQL需求响应从数周缩短至分钟级,业务自助成为可能
口径治理指标分散在不同数据集,依赖人工文档与沟通对齐定义即治理:一处定义,处处使用,创建时自动判重实现企业级指标口径100%一致,根治“数据打架”
性能与成本为保障查询性能,需预建大量汇总表,导致存储冗余与计算浪费智能物化加速:基于声明式策略,系统自动路由至最优物化结果释放1/3+服务器资源,TCO显著降低,实现亿级数据秒级响应

权威背书与客户验证:

  • 某头部券商(平安证券):引入后,指标开发效率提升 10 倍(取数周期从 2 周缩短至 1 天),指标口径实现 100% 一致,基础设施成本节约 50%。
  • 某全球连锁餐饮巨头(麦当劳中国):管理 8 大主题 1000+ 指标,在百亿级数据规模下,查询性能 P90 < 1 秒,日均支撑百万级 API 调用,实现了实时业绩监控与敏捷决策。
  • 某头部股份制银行:沉淀 1 万+ 指标,查询性能 <3 秒占比达 95%,数据交付效率提升 10 倍。

四、选型决策指南:你的企业更适合哪条路径?

选型决策应基于企业当前的数据成熟度、团队能力、业务诉求及战略规划进行综合判断。

优先选择 Aloudata CAN 的场景:

  1. 业务需求变化快:市场、运营等部门需要频繁进行探索性、灵活的分析,追求敏捷响应和实时决策。
  2. 深受指标治理之苦:企业内存在明显的“数据打架”现象,部门间因指标口径不一协同低效,管理层需要唯一可信的数据源。
  3. 希望提升团队效能:希望降低对稀缺的、专注于编写 ETL 脚本的数据工程师的依赖,赋能业务人员实现自助分析。
  4. 关注长期 TCO 与架构现代化:希望优化数据架构,降低冗余存储与计算成本,并为未来 AI 应用构建坚实的 AI-Ready 数据底座。
  5. 数字化初期企业:希望跳过“先乱后治”的痛苦阶段,直接采用先进的“语义模型驱动”架构,实现“弯道超车”和“数字化平权”。

可能暂缓考虑的场景:

  1. 现有基于宽表的报表体系非常稳定,且未来一段时间内无新的、灵活的分析需求。
  2. 技术团队资源充足,且已深度绑定并熟练使用特定的传统 ETL 工具链,业务对数据时效性要求极低(如 T+1 以上)。

落地策略建议:平滑演进“三步走”

对于大多数企业,我们推荐采用平滑演进策略,而非颠覆式重建:

  1. 存量挂载:将逻辑成熟、性能稳定的现有宽表直接挂载到平台,统一纳管口径,保护历史投资。
  2. 增量原生:所有新产生的分析需求,坚决采用“增量原生”模式,直连 DWD 明细层通过语义定义敏捷响应,从源头遏制宽表继续膨胀。
  3. 存量替旧:逐步将那些维护成本高、逻辑复杂、资源消耗巨大的“包袱型”旧宽表替换下线,迁移至语义模型。

五、常见问题 (FAQ)

Q1: 我们已经使用了现代云数仓,为什么还需要 Aloudata CAN 这样的语义编织层?

现代云数仓是强大的“存储与计算引擎”,解决了弹性伸缩问题。但业务灵活分析的需求,仍然需要通过人工开发大量物理宽表来满足,这导致了“最后一公里”的口径混乱和成本浪费。Aloudata CAN 是在这些强大引擎之上,构建统一、敏捷的“业务语义层”和“智能物化加速器”,让好引擎能持续、高效地产出可信、好用的数据,根治指标不一致问题。

Q2: 采用 NoETL 语义编织,是否意味着我们要完全抛弃和重写现有的 ETL 流程与宽表?

并非如此。推荐采用“存量挂载+增量原生”的混合策略。对于逻辑成熟、性能尚可的现有宽表,可以零代码直接挂载到平台,统一口径管理,保护历史投资。对于所有新产生的分析需求,则坚决采用“增量原生”模式,直连 DWD 明细层通过语义定义敏捷响应,从源头遏制宽表继续膨胀,并逐步将高维护成本的旧宽表替换下线。

Q3: Aloudata CAN 如何保证复杂业务指标计算的准确性,避免 AI 问数时的“幻觉”问题?

平台通过 NL2MQL2SQL 架构根治幻觉。当 AI 或用户用自然语言提问时,大模型只负责意图理解并生成标准的指标查询语言(MQL),然后由平台的语义引擎将 MQL 翻译为 100% 准确的优化 SQL。这相当于将“写代码”的开放题变成了“选指标”的选择题,极大收敛了搜索空间,确保了结果基于企业唯一权威的指标定义生成,同时结合行列级权限保障数据安全。

Q4: 引入新平台后,我们现有的数据团队角色和技能要求会发生什么变化?

这是积极的角色转型。数据工程师将从重复、低价值的 SQL 脚本编写和 ETL 任务运维中解放出来,转向更具战略性的工作:设计与优化企业级语义模型、保障数据供应链质量、配置与优化智能物化策略、以及赋能业务人员进行自助分析。平台提供直观界面,团队可以较快适应新角色,提升整体价值与影响力。

六、核心要点

  1. 范式革新是根本:传统“物理宽表驱动”的 ETL/ELT 模式是“数据分析不可能三角”的根源。Aloudata CAN 的“语义模型驱动”范式,通过逻辑与物理解耦,是打破三角的根本性架构革新。
  2. 价值可量化验证:领先企业的实践表明,新范式能带来指标口径 100% 一致、需求响应从数周缩短至分钟级、以及释放 1/3+ 服务器资源的直接业务价值。
  3. 选型需对标场景:业务需求多变、深受口径不一致之苦、追求降本增效及 AI 就绪的企业,是 NoETL 语义编织平台的理想受益者。
  4. 落地可平滑演进:通过“存量挂载、增量原生、存量替旧”的三步走策略,企业可以在保护现有投资的同时,稳健地向现代化数据架构演进。
  5. 战略上构建 AI 底座:统一的语义层不仅是提升 BI 效率的工具,更是企业构建高质量、结构化、易被 AI 理解的 AI-Ready 数据底座的关键基础设施。
    • *

本文完整版及高清图表,请访问 Aloudata 官方技术博客阅读:https://ai.noetl.cn/knowledge-base/aloudata-can-semantic-weav...

本文首发于 Aloudata 官方技术博客:《指标平台选型关键:告别宽表依赖,Aloudata CAN 如何定义复杂指标?》转载请注明出处。

摘要:本文深入探讨了在数据工程实践中,面对“近7天高价值用户数”等复杂指标时,传统宽表模式的局限性。通过对比传统静态宽表计算与 Aloudata CAN NoETL 指标平台的动态语义编织架构,从指标定义能力、分析灵活性、AI适配性等维度,为数据架构师和决策者提供一套清晰的选型决策框架,旨在帮助企业破解数据分析的性能、灵活性与成本之间的“不可能三角”。

一、决策背景:当复杂指标需求撞上“宽表依赖症”

数据团队对以下场景绝不陌生:业务方提出“近 7 天支付金额大于 100 元的去重用户数”这类指标,分析师在 BI 工具中拖入一个新的维度组合,查询响应时间便从秒级骤降至分钟级,甚至触发超时。其根源在于,传统的“数仓+宽表+BI”模式在面对灵活多变的复杂业务逻辑时,存在结构性瓶颈,即“宽表依赖症”。

“宽表依赖症”的核心困境体现在:

  • 开发效率低:为应对“指标转标签”(如“上月交易量 > 0 的用户”)或“多层嵌套聚合”(如“月日均交易额最大值”)等复杂逻辑,数据工程师需编写数百行 SQL,构建物理宽表。需求排期以周甚至月计,无法支持业务快速迭代。
  • 分析不灵活:分析路径被预建的物理宽表(ADS 层)所固化。一旦业务提出未预见的维度组合(如新增“用户等级”维度),就必须启动新一轮的宽表开发排期,严重制约了业务探索性分析。
  • 成本高昂:为满足不同分析场景,大量宽表和汇总表被重复开发,导致存储与计算资源严重浪费,形成“烟囱式”的数据资产。

“在指标平台等分析场景下,数据量往往达到亿级甚至更高。查询缓慢、响应延迟成为常态,严重影响了业务人员获取数据的时效性。” —— 镜舟科技技术博客

这种模式在追求极致分析性能、灵活性和成本效益之间难以找到平衡点,构成了数据分析的“不可能三角”。

二、核心差异:静态宽表计算 vs 动态语义编织

性能与灵活性困境的根本差异,源于底层架构的范式革新。

传统模式(静态宽表计算):其核心是 “预计算、后查询” 。数据分析师或开发人员需要预先理解业务需求,编写 SQL 或 ETL 任务,将多张表打平成物理宽表或汇总表。查询时,BI 工具直接访问这些固化好的物理表。其性能上限在宽表创建时即被锁定,且无法应对未预见的查询模式。

Aloudata CAN NoETL 模式(动态语义编织):其核心是 “声明定义、动态计算” 。基于语义编织技术,用户在界面通过 声明式策略 完成两件事:

  • 声明逻辑关联:在未打宽的 DWD 明细表之间,声明业务实体间的关联关系(如 订单表 JOIN 用户表)。
  • 声明指标逻辑:通过配置“基础度量、业务限定、统计周期、衍生计算”四大语义要素来定义指标。
    系统据此在逻辑层构建一个 虚拟业务事实网络(或称虚拟明细大宽表)。当业务发起查询时,语义引擎 将查询意图翻译为最优化的 SQL,并通过 智能物化引擎 透明路由至已预热的物化结果或高效执行原生查询。这是一种 “逻辑定义与物理执行解耦” 的架构。

三、维度对比一:复杂指标定义能力

面对复杂的业务逻辑,两种模式在定义方式、效率和维护性上存在天壤之别。

对比维度传统宽表模式Aloudata CAN NoETL 模式
定义方式编写数百行 SQL,人工开发,依赖资深工程师声明式配置,零代码定义,业务分析师即可完成
典型场景简单聚合(如销售额、订单数)指标转标签(如“上月交易>0的用户”)、多层嵌套聚合(如“月日均最大值”)、跨表复合指标(如“渠道ROI”)
开发效率低,需求排期以周/月计,响应迟缓高,分钟级完成定义与交付,实现业务自助
维护成本高,逻辑变更需重写 SQL 与 ETL,牵一发而动全身低,配置化修改,系统自动同步所有下游,治理内嵌于流程

核心差异解读:传统模式将复杂的业务逻辑固化在物理表结构中,变更成本极高。而 Aloudata CAN 通过语义抽象,将指标转化为可配置的要素,实现了 “定义即开发” 。例如,定义“近 30 天有购买行为的用户”这一标签,只需选择“交易金额”作为基础度量,设置“统计周期”为近 30 天,“业务限定”为“交易金额 > 0”,系统即自动生成并执行相应的去重计数逻辑,无需编写一行 JOIN 和 GROUP BY 的 SQL。

四、维度对比二:分析灵活性与性能保障

当业务需要自由探索数据时,两种架构对分析路径和查询性能的保障机制截然不同。

  • 传统模式:分析灵活性被物理宽表预先定义好的维度组合所限制。任何未预见的查询都可能导致性能“开盲盒”,直接扫描亿级明细,响应时间无法保障。
  • Aloudata CAN:支持指标与维度任意组合、自由下钻。其性能通过 声明式物化策略 保障:用户可声明对特定指标和维度组合进行加速,系统据此自动编排物化任务并维护物化视图(预汇总结果)。查询时,智能物化引擎 自动进行 SQL 改写和路由,透明命中最优物化结果,实现热点查询的秒级响应。

这种性能已在客户实践中得到验证。例如,某全球连锁餐饮巨头 在 Aloudata CAN 上沉淀了 8 大主题 1000+ 指标、250+ 维度,面对百亿级数据规模,实现了 P90 响应时间 < 1 秒,日均稳定支撑百万级 API 调用,彻底解决了性能与灵活性的矛盾。

五、维度对比三:AI 适配与未来扩展性

AI 时代,尤其是对话式数据分析(ChatBI)的兴起,对数据的语义一致性和接口确定性提出了更高要求。

传统模式:无法为 AI 提供统一的、业务友好的语义接口。大模型(LLM)直接面对杂乱无章的物理表生成 SQL,极易产生“数据幻觉”,且无法进行有效的权限管控。

Aloudata CAN:原生 AI-Ready,其核心是 NL2MQL2SQL 架构:

  • NL2MQL:LLM 负责理解用户自然语言问题,并生成标准的指标查询语言(MQL),这是一个收敛了搜索空间的“选择题”。
  • MQL2SQL:语义引擎 将 MQL 翻译为 100% 准确的、经过优化的 SQL,并利用智能物化引擎加速。
  • 安全层:请求先经语义层鉴权,验证通过后才执行,杜绝 AI 越权访问,实现“先安检,后执行”。

作为 《数据编织数据虚拟化平台技术要求》等标准的核心起草单位,Aloudata CAN 的语义层本质上是一个高度浓缩的业务知识图谱,为 RAG(检索增强生成)提供了最佳语料,确保 AI 能以极低的成本获得极高的上下文精准度,从源头根治幻觉。

六、综合选型建议:基于企业数据成熟度决策

没有“最好”的平台,只有“最适合”当前阶段和未来需求的平台。决策应基于企业的数据规模、业务灵活性需求及 AI 战略。

决策路径参考:

场景 A(数据量 < 千万级,报表需求固定)

  • 特征:数据量小,业务分析维度相对固化,暂无 AI 问数需求。
  • 建议:传统数仓宽表模式或主流 BI 工具内置的数据集仍可有效应对,引入自动化平台的投资回报率(ROI)可能不高。

场景 B(数据量达亿级或更高,业务查询需求灵活多变)

  • 特征:面临“宽表依赖症”的典型痛点,业务希望自由下钻分析,但对查询延迟敏感。
  • 建议:强烈建议评估 Aloudata CAN 这类 NoETL 指标平台。其动态语义编织和智能物化加速能力,能在保障秒级响应的同时,提供极大的分析灵活性,从根本上破解性能与灵活性的矛盾。可参考 某头部券商 的实践:实现开发效率 10 倍提升,基础设施成本节约 50%。

场景 C(高并发查询 + AI 智能问数需求)

  • 特征:需要面向大量业务用户或应用系统提供稳定、统一的数据服务,并计划引入自然语言查询数据。
  • 建议:必须选择具备 NL2MQL2SQL 能力的 AI-Ready 数据底座。Aloudata CAN 的语义层为 AI 提供了精准、安全的唯一指标化访问接口,是构建可靠数据智能应用的必备基础。

对于数字化初期的企业,采用 NoETL 架构更是一种 “弯道超车” 的机会,能跳过“先乱后治”的传统数据建设阶段,直接构建统一、敏捷的数据服务能力。

七、常见问题 (FAQ)

Q1: 什么是“无宽表计算”?它如何保证查询性能?

“无宽表计算”指不依赖预建的物理宽表,而是通过语义编织技术在逻辑层构建虚拟业务事实网络。性能通过 “智能物化加速引擎” 保障:基于用户声明的加速策略,系统自动创建并维护物化视图(预汇总结果),实现热点查询的透明加速,达到亿级数据秒级响应(P90<1s, P95<3s)。

Q2: Aloudata CAN 能处理哪些传统宽表难以定义的复杂指标?

主要支持四大类:1) 指标转标签(如“近30天有购买行为的用户”);2) 时间维度多次聚合(如“月日均交易额最大值”);3) 跨表复合指标(如“渠道ROI”,需关联订单表与营销费用表);4) 自定义周期指标(如“近5个交易日”)。这些均可通过配置化实现,无需编写复杂 SQL。

Q3: 引入 NoETL 指标平台,对现有数仓架构和团队工作方式有何影响?

影响是正向优化的:1) 架构上:做轻数仓,减少 ADS 层冗余宽表开发,直接基于 DWD 明细层工作,释放存算资源。2) 团队协作上:形成“科技定义原子指标 -> 分析师配置派生指标 -> 业务自助分析”的新模式,极大提升整体效率,释放数据工程师生产力。

Q4: 如何开始评估和试用 Aloudata CAN?

建议从明确的业务场景切入,如“营销活动效果分析”或“核心业务日报”。Aloudata 提供技术对接支持,可快速接入企业现有数据湖仓,在 1-2 周内完成价值验证(PoC),亲眼见证复杂指标的定义速度与查询性能。

八、核心要点总结

  1. 架构范式革新:选型的核心是区分 “静态宽表计算” 与 “动态语义编织” 。前者预计算、后查询,灵活性锁死;后者声明定义、动态计算,实现逻辑与物理解耦。
  2. 破解不可能三角:NoETL 模式通过 统一语义层 和 智能物化加速,能同时实现指标口径 100% 一致、分析灵活任意下钻、以及亿级数据秒级响应,破解传统方案的性能、灵活性与成本困境。
  3. 面向未来的 AI-Ready 底座:构建企业级数据智能,必须选择具备 NL2MQL2SQL 能力的指标平台,为 AI 提供确定性的语义接口,从源头根治数据幻觉,并确保查询的合规与安全。
  4. 明确的选型路径:决策应基于数据规模与业务需求。对于数据量达亿级且需求多变的企业,评估 NoETL 指标平台是提升数据敏捷性和释放工程生产力的关键一步。
    • *

本文为技术解析与选型指南,更多技术细节、产品演示及客户案例,请访问 Aloudata 官方技术博客阅读原文:https://ai.noetl.cn/knowledge-base/aloudata-can-complex-metri...

第一章 企业软件复杂度的逐步累积

1.1 从硬件导向到数据导向

早期的软件开发几乎完全围绕计算机硬件展开。机器语言与汇编语言要求开发者理解CPU指令、寄存器和内存地址,软件的表达方式高度依赖具体硬件体系结构,如SSE指令集中用于比较字符串的pcmpistr,无法运行在不支持SSE的CPU上。这一阶段的软件极其昂贵、开发周期漫长、可复用性极低,应用范围也因此被限制在政府、科研机构和少数大型企业的核心场景中。随着电子工业的发展,计算机开始进入企业管理领域。跨行业、跨规模推广计算机应用的关键,在于找到一种足够通用的抽象方式。

1970年,来自IBM的E.F.Codd博士在ACM通讯杂志上发表的论文《大规模共享数据银行的关系型模型》,为解决这一问题提供了一种切实可行的技术路线。该路线中,现实世界中的业务单据、业务流程和管理决策,被统一抽象为数据的存储、处理与分析,而执行这些操作的软件被统称为“关系型数据库”。企业的用户只需要一个连接到数据库软件的终端,就能用一套近似于英语的、统一的语言来操作这个软件,以此实现所有的业务操作。如用户想要查询姓名中包含“李”的员工档案,需要输入 SELECT * FROM STAFFS WHERE NAME LIKE ‘%李%’ ,界面上就会呈现出纯文本呈现的员工档案信息。

image

图:早期的数据库服务器与操作终端

关系型数据库的出现,标志着企业软件第一次在抽象层面实现了规模化。通过关系模型描述业务实体及其关系,通过统一的数据操作语言处理不同业务场景,数据库成功降低了企业信息化的技术门槛,也显著扩展了软件需求的边界。

1.2 “壳”的出现与复杂度外溢

当数据库从档案管理走向财务、库存、成本核算等复杂业务场景时,一个新的问题随之出现:直接操作SQL对最终用户并不友好,一个业务操作需要多次打印和重复输入,导致操作员工作负荷高、出错概率大。为此,行业选择将数据库抽象为数据模型(数据模型可近似理解为数据库的结构,由数据表、列和表关系构成),在模型之上构建应用软件。这种做法很像是给数据库“套壳”,让用户操作应用,应用去操作数据库,而非用户直接操作数据库。

这一决策带来了企业软件形态的根本变化。业务逻辑开始在数据库与应用程序之间重新分配,用户交互界面成为差异化竞争的核心。随着抽象度更高的新一代高级语言(如C++、Java语言)在应用层的普及,企业软件正式进入“高级语言 + 数据库”的长期技术范式。

image

图:DOS时代的企业软件操作界面

然而,这种分层结构也埋下了复杂度累积的种子:

  • 数据模型持续膨胀:一个小型订单管理系统可能只有十几张表,但经过几年演进后,堪比ERP的系统重,表数量可能增长到数百张
  • 业务规则不断叠加:每次业务流程调整都会增加新的验证规则、计算公式和例外处理逻辑
  • 交互逻辑日益复杂:从简单的表单录入发展到复杂的向导流程、多标签页面和实时校验
  • 应用规模和生命周期显著拉长:企业软件往往需要运行十年甚至更长时间,期间不断打补丁和加功能

企业软件不再是一次性交付的工具,而是需要多年演进、持续维护的复杂系统。

扩展链接

写给技术管理者的低代码手册系列文章(1)——从软件工程视角理解低代码的价值、边界与演进路径

前面的章节(社区专栏《SQL调优》)我们已经写了很多篇幅关于 MySQL 执行计划的解读,今天我们来继续延伸介绍执行计划的链路跟踪功能,也就是 MySQL 的 Optimizer Trace

在这之前,先来回顾下 EXPLAIN 的结果:

mysql:ytt>explain select * from t1 a left join y1 b on a.id = b.id where a.r1<100 order by a.r2 desc;
+----+-------------+-------+------------+--------+---------------+---------+---------+----------+--------+----------+-----------------------------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref      | rows   | filtered | Extra                       |
+----+-------------+-------+------------+--------+---------------+---------+---------+----------+--------+----------+-----------------------------+
|  1 | SIMPLE      | a     | NULL       | ALL    | idx_r1        | NULL    | NULL    | NULL     | 998222 |    50.00 | Using where; Using filesort |
|  1 | SIMPLE      | b     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | ytt.a.id |      1 |   100.00 | NULL                        |
+----+-------------+-------+------------+--------+---------------+---------+---------+----------+--------+----------+-----------------------------+
2 rows in set, 1 warning (0.00 sec)

EXPLAIN 展示出来的核心数据有:

  1. 表关联顺序
  2. 优化器筛选过的索引
  3. 实际使用的索引
  4. 每张表依据统计信息的扫描行数
  5. Extra 额外数据提示
  6. 两种执行计划(explain format=tree / explain format=json)展示出来的额外成本数据

如果想快速对于 SQL 进行优化,基于以上的结果完全可以满足。但是想深入了解 MySQL 优化器为什么选择这样的执行计划,基于以上的结果就无法满足。

举例说明:

  • 我想知道对于表 a 来讲,为什么有索引 idx_r1,但是实际却没有使用,而走的全表扫?
  • 两张表关联,为什么选择的顺序是表 a 驱动表 b,而不是表 b 驱动表 a
  • 为什么字段 r2 有索引,但是依然要走排序?

带着这些疑问,我们来介绍 MySQL 的 Optimizer Trace 功能。

1. 什么是 Optimizer Trace?

简单来讲,Optimizer Trace 是一个 SQL 执行计划的链路跟踪器,跟踪 SQL 的解析、优化、执行等过程,并且把结果记录到 MySQL 元数据表(information_schema.optimizer_trace),之后可以对这张表分析得到很多个执行计划的“为什么?”!

2. 如何使用 Optimizer Trace?

要使用 Optimizer Trace 功能,首先得打开控制开关。谨记:这个功能非常耗费资源,默认关闭的,可以通过调整以下变量开启:

mysql:ytt>show variables like 'optimizer_trace%';
+------------------------------+----------------------------------------------------------------------------+
| Variable_name                | Value                                                                      |
+------------------------------+----------------------------------------------------------------------------+
| optimizer_trace              | enabled=off,one_line=off                                                   |
| optimizer_trace_features     | greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on |
| optimizer_trace_limit        | 1                                                                          |
| optimizer_trace_max_mem_size | 1048576                                                                    |
| optimizer_trace_offset       | -1                                                                         |
+------------------------------+----------------------------------------------------------------------------+
5 rows in set (0.00 sec)

以上几个参数详细解释下:

  • optimizer_traceenabled=on/off 启用/禁用 Optmizer Trace 功能;one_line=on/off 启用/禁用 json 格式化存储,一般不需改动。
  • optimizer_trace_limit/optimizer_trace_offset:这两个参数和 LIMIT 子句一样,用来最终展示 Trace 的 SQL 条数。展示的条数越多,对内存消耗越大,默认展示最近的一条记录。比如设置 optimizer_trace_limit 为 10,optimizer_trace_offset 为 -10,就可以最多展示 10 条 Trace 记录。
  • optimizer_trace_max_mem_size:用来存储 Trace 结果的最大内存。
  • optimizer_trace_features:用来启动/禁用相关 Trace 特性开关。
  • end_markers_in_json:启用/禁用 注释功能。开启这个,Trace 结果可读性更强。
  • Optimizer Trace 可以跟踪的语句有:

    • SELECT、TABLE、VALUES、WITH、INSERT、REPLACE、UPDATE、DELETE
    • EXPLAIN
    • SET(排除设置 Optimizer Trace 相关参数)
    • DO
    • 存储函数内部、触发器内部等的 DECLARE、CASE、IF、RETURN 语句
    • CALL
在数据库里,语句调优一般说的是 SELECT 语句,所以大部分场景跟踪的也只有 SELECT 语句。

元数据表字段解析

mysql:ytt>desc information_schema.optimizer_trace;
+-----------------------------------+----------------+------+-----+---------+-------+
| Field                             | Type           | Null | Key | Default | Extra |
+-----------------------------------+----------------+------+-----+---------+-------+
| QUERY                             | varchar(65535) | NO   |     |         |       |
| TRACE                             | varchar(65535) | NO   |     |         |       |
| MISSING_BYTES_BEYOND_MAX_MEM_SIZE | int            | NO   |     |         |       |
| INSUFFICIENT_PRIVILEGES           | tinyint(1)     | NO   |     |         |       |
+-----------------------------------+----------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
  • QUERYTRACE 的 SQL 语句原文
  • TRACE:SQL 语句的 TRACE 结果,JSON 格式存储(由变量 end_markers_in_json 来控制)
  • MISSING_BYTES_BEYOND_MAX_MEM_SIZETRACE 结果超过变量 optimizer_trace_max_mem_size 设置的值后,截断的大小(BYTE)
  • INSUFFICIENT_PRIVILEGES:对存储过程、存储函数等包含有 SQL SECURITY DEFINER 的用户是否有对应的权限,有权限为 0,无权限为 1,并且 TRACE 字段为空。

Optimizer Trace 开启步骤

mysql:ytt>set optimizer_trace='enabled=on';
Query OK, 0 rows affected (0.00 sec)

mysql:ytt>set optimizer_trace_limit=10;
Query OK, 0 rows affected (0.00 sec)

mysql:ytt>set optimizer_trace_offset=-10;
Query OK, 0 rows affected (0.00 sec)

mysql:ytt>set end_markers_in_json=on;
Query OK, 0 rows affected (0.00 sec)

这里要注意的是,修改任何一个 Optimizer Trace 相关参数,元数据表 information_schema 表都会被清空。

mysql:ytt>select count(*) from information_schema.optimizer_trace;
+----------+
| count(*) |
+----------+
|       10 |
+----------+
1 row in set (0.00 sec)

mysql:ytt>set optimizer_trace_offset=-2;
Query OK, 0 rows affected (0.00 sec)

mysql:ytt>select count(*) from information_schema.optimizer_trace;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

3. Optimizer Trace 的结果

我们用一个最简单的例子来看看 Optimizer Trace 的大致结构:do 语句非常简单,只用来验证是否语法正确,不出结果。

mysql:ytt>do 1+1;
Query OK, 0 rows affected (0.00 sec)

下面是 Optimizer Trace 结果:

mysql:ytt>select query,trace from information_schema.optimizer_trace\G
*************************** 1. row ***************************
query: do 1+1
trace: {
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select (1 + 1) AS `1+1`"
          }
        ]
      }
    },
    {
      "join_optimization": {
        "select#": 1,
        "steps": [
        ]
      }
    },
    {
      "join_execution": {
        "select#": 1,
        "steps": [
        ]
      }
    }
  ]
}
1 row in set (0.00 sec)

可以看到,Optimizer Trace 结果是一个 JSON 串,keystepsvalue 是一个数组,数组有三个 key,分别为:

  • join_preparation 准备阶段:这里会做一些 SQL 改写,关键字识别等等,可以看到 expanded_query 对应的值即为 SQL 语句被改写后的内部 SQL。
  • join_optimization 优化阶段:具体 SQL 优化,包括一些可能的逻辑优化,一些根据表统计信息预估的物理优化等等。
  • join_execution 最终执行阶段:最终 SQL 采用的执行计划等等。

本篇是Optimizer Trace的开端,由于内容太多,我特地拆分为几篇来写,欢迎继续订阅。

640 (84).webp

Google 近期针对 BigQuery 推出了面向开源模型的第三方生成式 AI 推理功能。这一更新允许数据团队直接使用简单的 SQL 语句,部署并运行来自 Hugging Face 或 Vertex AI Model Garden 的任何模型。该接口目前处于预览阶段,其最大的亮点在于消除了对独立机器学习(ML)基础设施的需求,系统会自动启动计算资源、管理端点,并在任务完成后通过 BigQuery 的 SQL 接口自动清理资源。

这项新功能解决了困扰数据团队已久的痛点。在过去,运行开源模型往往意味着需要管理 Kubernetes 集群、配置端点以及在多种工具之间反复切换。Virinchi T 在一篇关于此次发布的 Medium 文章中指出:

这一过程需要多种工具协同、不同的技能储备以及巨大的运维开销。对于许多数据团队来说,这种摩擦意味着即便模型本身是免费且公开的,AI 能力依然显得遥不可及。

然而,得益于 BigQuery 的 SQL 接口,整个工作流现在被简化为仅需两条 SQL 语句。用户首先通过一条 CREATE MODEL 语句来创建模型,只需指定 Hugging Face 的模型 ID(例如 sentence-transformers/all-MiniLM-L6-v2)或 Vertex AI Model Garden 中的模型名称。BigQuery 会根据默认配置自动分配计算资源,部署过程通常在 3 到 10 分钟内即可完成,具体时长取决于模型大小。

部署完成后,用户可以使用 AI.GENERATE_TEXT(针对语言模型)或 AI.GENERATE_EMBEDDING(针对嵌入模型)直接对 BigQuery 表中的数据进行推理查询。平台通过 endpoint_idle_ttl 选项管理资源的生命周期,该功能会自动关闭闲置端点以节省费用。此外,在批处理任务结束后,用户还可以通过 ALTER MODEL 语句手动卸载端点。

为了满足生产环境的需求,该功能还支持高度定制化。用户可以直接在 CREATE MODEL 语句中设定机器类型、副本数量以及端点闲置时间。通过 Compute Engine 预留功能,还可以锁定 GPU 实例以确保性能稳定。当不再需要某个模型时,只需执行一条简单的 DROP MODEL 语句,系统便会自动清理所有关联的 Vertex AI 资源。

Google 在官方博客中将该系统描述为提供“精细的资源控制”和“自动化的资源管理”,旨在让团队在不脱离 SQL 环境的情况下,找到性能与成本之间的最佳平衡点。2025 年 9 月发布的一篇早期博客曾展示,利用类似的开源嵌入模型处理 3800 万行数据,成本仅需约 2 到 3 美元。

目前,该功能已支持超过 1.3 万个 Hugging Face 文本嵌入模型和超过 17 万个文本生成模型,涵盖了 Meta 的 Llama 系列和 Google 的 Gemma 家族。需要注意的是,所选模型必须符合 Vertex AI Model Garden 的部署要求,包括区域可用性和配额限制。

Virinchi T 强调了这一变革对不同角色的意义:

对于数据分析师而言,你现在可以无需离开 SQL 环境,也不必等待工程资源支持,就能直接实验 ML 模型。对于数据工程师而言,构建由机器学习驱动的数据管道变得极其简单,再也不用维护独立的 ML 基础设施。

此次发布标志着 BigQuery 将与 Snowflake 的 Cortex AI 以及 Databricks 的 Model Serving 展开直接竞争,后两者同样提供基于 SQL 的 ML 推理能力。而 BigQuery 的竞争优势可能在于其与 Hugging Face 庞大模型库在数据仓库内的深度集成,这对于已经在 Google Cloud 上运行业务的用户具有极强的吸引力。

目前,关于 Gemma 模型的文本生成以及嵌入生成的相关文档和教程已正式上线。

原文链接:

https://www.infoq.com/news/2026/01/bigquery-sql-huggingface-managed/

本文首发于 Aloudata 官方技术博客:《为什么公司会有几百个含义模糊的“DAU”指标?深度解析》转载请注明出处。

摘要:企业数据治理中普遍存在数百个同名不同义的“DAU”指标,这并非管理失误,而是传统“数仓+BI”烟囱式架构的必然结果。本文将从数据工程视角,精确定义指标口径混乱的四大要素,剖析其三大结构性根源,并阐述如何通过构建基于 NoETL 语义编织技术的统一指标平台,实现“一次定义,处处使用”,从根本上解决数据分析的“不可能三角”难题。

“数据孤岛导致的‘同源不同口径’问题日益严重。不同业务系统独立运行,产生的数据没有统一的描述体系。结果就是:明明是同一个‘活跃用户’指标,财务、市场和运营的口径却完全不同。这会直接导致数据驱动的决策不一致。” —— 行业分析报告

当一家企业的数据团队发现,他们维护着数百个名为“DAU”(日活跃用户)或“销售额”的指标,而每个指标的计算逻辑、统计周期或业务限定都略有不同时,这通常不是某个部门或个人的失误。相反,这是传统数据架构模式下的一个必然结果。

在经典的“数仓+BI”模式中,业务需求驱动着漫长的物理开发链路:一个报表需求 → 数据工程师开发 ETL 任务 → 创建特定的物理宽表(DWS/ADS 层) → BI 工具连接该宽表生成报表。这种“为特定报表建特定宽表”的烟囱式开发,将指标逻辑固化并分散在了成百上千个物理表中。每一次新的分析视角,都可能催生一张新的宽表和一个“略有不同”的指标版本。这直接导致了数据分析的“不可能三角”:在口径一致、响应敏捷和深度洞察三者之间难以兼得。

精确定义:什么才是真正的“指标口径混乱”?

指标口径混乱并非一个模糊的概念,它特指同一业务术语在不同数据消费场景中,其核心语义要素存在不一致,从而导致决策依据相互矛盾。一个完整的指标定义包含四大语义要素,任何一处的差异都可能导致“混乱”:

  1. 基础度量:核心的聚合计算,如COUNT(DISTINCT user_id)SUM(order_amount)
  2. 统计周期:数据统计的时间范围,如“当日”、“近7日滚动”、“本财年至今”。
  3. 业务限定:对数据范围的筛选条件,如“状态为‘已支付’”、“用户渠道为‘APP’”。
  4. 衍生计算:基于基础度量的二次计算,如同环比、占比、排名。

例如,市场部的“DAU”可能统计所有启动 APP 的设备,而财务部的“DAU”可能只统计完成至少一次有效交易的用户。这不仅仅是“活跃”定义的差异,更是基础度量(是否去重)和业务限定(是否包含交易行为)的双重不一致。

核心要素:导致指标泛滥的三大“元凶”

指标混乱现象是技术架构、组织协作和工具生态三个层面因素共同作用的“完美风暴”。

要素一:烟囱式的物理宽表开发

这是最根本的技术原因。每个分析需求都对应一张(或多张)物理宽表,指标逻辑被硬编码在 SQL 和表结构中。当业务规则变更(如“活跃”定义调整)时,需要追溯并修改所有相关的宽表,成本极高且极易遗漏,导致历史数据对比失真。

要素二:部门墙与协作断层

业务方、数据分析师与数据开发团队之间缺乏统一的协作语言和平台。需求通过邮件、会议口头传递,容易产生歧义。各部门为追求自身效率,在本地数据集或临时查询中定义“自己版本”的指标,形成组织内的“数据方言”。

要素三:封闭的 BI 工具内置指标

主流 BI 工具为提升易用性,内置了指标定义模块。然而,这些指标定义被绑定在特定的 BI 工具前端。当企业使用多套 BI 工具(如总部用 A,业务部门用 B),或需要向 AI 大模型、自建应用提供数据服务时,这些封闭的指标定义无法被复用,形成了新的“工具孤岛”。

常见误区:关于指标治理的四个错误认知

许多企业意识到问题,却采用了错误的方法,反而加剧了困境。

误区错误本质导致的后果
误区一:建一个指标字典就够了将指标治理等同于建立静态的元数据目录(Catalog)。目录与计算脱节,业务人员查阅字典后,仍需找开发人员从物理宽表中取数,口径落地依赖人工,无法保证一致性。
误区二:强制统一所有报表采用行政命令,要求所有部门立即废弃原有报表,使用统一模板。忽视业务敏捷性,引发业务部门强烈抵触,治理行动难以推进,甚至催生更隐蔽的“影子报表”。
误区三:选择一个BI工具统一天下试图通过采购单一BI厂商的全套方案来解决所有问题。被单一厂商绑定,丧失技术选型灵活性;无法适应不同场景的多样化需求(如 AI 调用、嵌入式分析)。
误区四:指标治理是IT部门的事认为制定标准、维护口径是数据团队的技术职责。缺乏业务方的深度参与和共识,制定的标准脱离实际业务场景,治理成果无法在业务决策中落地。

企业价值:终结指标混乱带来的四大收益

解决指标口径问题,远不止于“统一语言”,它能直接转化为可量化的业务与技术收益。

  1. 决策一致:基于同一事实决策,彻底避免部门间因数据“对不上”而产生的无谓争论与信任损耗,提升组织协同效率。
  2. 响应敏捷:业务人员通过自助式拖拽分析,无需等待排期,将分析需求响应周期从“天级”压缩至“分钟级”,快速验证业务假设。
  3. 洞察深化:突破预建宽表的维度限制,支持对指标进行任意维度、任意粒度的灵活下钻与归因分析,从“描述现象”走向“解释原因”。
  4. 成本降低:通过做轻数仓,减少甚至消除大量重复的 DWS/ADS 层物理宽表开发与维护,可释放 30% 以上的服务器计算与存储资源。

案例佐证:某头部股份制银行通过引入统一指标平台,实现了总分行指标口径 100% 一致,数据交付效率提升 10 倍(从 2 周缩短至 1 天),并沉淀了超过 1 万个可复用的标准指标。

评估清单:你的企业是否已陷入指标泥潭?

请用以下 5 个问题快速自检:

  1. 同一个核心业务指标(如“销售额”、“利润率”),财务、市场、运营等部门给出的数字是否经常对不上,需要反复核对?
  2. 业务部门提出一个新的报表或分析需求,从提出到最终上线,平均排期是否超过 1 周?
  3. 业务人员能否在不求助数据团队的情况下,自主、灵活地切换分析维度(如从“按地区看”切换到“按产品品类看”)?
  4. 数据团队是否花费大量时间,疲于维护众多业务逻辑相似但略有不同的汇总表、宽表?
  5. 当企业引入新的 BI 工具或AI智能问数应用时,是否需要数据团队重新定义、开发一套指标?

如果上述问题有两个或以上的答案是肯定的,那么您的企业很可能已经深受指标混乱之苦。

解决方案:基于 NoETL 语义编织的统一指标平台

要根治上述问题,需要从架构层面进行革新,将指标的定义、计算与服务进行逻辑解耦。这正是 Aloudata CAN NoETL 指标平台的核心。

核心理念:定义即开发,定义即服务

平台基于 NoETL 语义编织 技术,允许用户在逻辑层面进行声明式定义:

  • 逻辑关联声明:在 DWD 明细层上,声明业务实体间的关联关系,构建“虚拟业务事实网络”,无需预先物理打宽。
  • 声明式指标定义:通过配置化方式,组合“基础度量、统计周期、业务限定、衍生计算”四大语义要素,零代码定义复杂指标(如“上月高价值用户复购率”)。
  • 智能物化加速:基于用户声明的加速策略(而非全自动感知),系统自动生成并维护物化视图,查询时智能路由,实现亿级数据秒级响应。

架构对比:从“烟囱林立”到“统一语义层”

  • 传统架构(左):需求驱动,层层物理建模,形成大量 DWS/ADS 宽表,指标逻辑分散且固化。
  • NoETL架构(右):统一的语义层直接对接 DWD 明细数据,逻辑定义指标,向上通过标准 API/JDBC 服务各类消费端(BI、AI、应用)。

关键价值:成为 AI-Ready 的数据底座

混乱的指标和元数据是导致AI智能问数产生“幻觉”的主因。统一指标平台通过构建高质量的语义知识图谱,为 AI 提供了精准的上下文。

  • 根治幻觉:采用 NL2MQL2SQL 架构。用户用自然语言提问 → LLM 理解意图生成指标查询语言(MQL)→ 平台语义引擎将 MQL 转换为 100% 准确的优化 SQL。
  • 安全可控:所有 AI 数据请求先经过语义层鉴权,确保符合行列级数据安全策略,实现“先安检,后执行”。

常见问题 (FAQ)

Q1: 我们公司已经用了主流 BI 工具,为什么还需要独立的指标平台?

因为传统 BI 工具的指标定义是内置且绑定在该工具前端的,本质是增强工具粘性的功能模块。当企业存在多套BI工具,或需要向 AI 大模型、自建应用、WPS 表格插件等提供数据服务时,这些封闭的指标定义无法被复用。独立的指标平台作为中立的 Headless 基座,提供统一的标准 API,确保全企业“一次定义,处处使用”,口径 100% 一致。

Q2: 统一指标平台和传统数据中台里的指标管理有什么区别?

传统数据中台的指标管理多是“静态目录”,只记录指标元数据(如名称、口径描述),实际计算仍依赖底层人工开发、运维的物理宽表。而现代化的统一指标平台(如 Aloudata CAN)本身是一个动态计算引擎。它基于 NoETL 语义编织技术,直接在 DWD 明细层上通过声明式方式定义指标逻辑,并自动完成计算、物化加速与查询服务,实现了“定义即开发、定义即服务”。

Q3: 实现指标统一,是不是意味着要推翻现有的数据仓库重来?

完全不需要。推荐采用渐进式的 “三步走”资产演进法则:

  1. 存量挂载:将现有逻辑成熟、性能稳定的物理宽表直接挂载到平台,快速统一查询出口。
  2. 增量原生:所有新的分析需求,直接基于 DWD 明细层在平台上通过声明式定义敏捷响应,遏制宽表继续膨胀。
  3. 存量替旧:逐步将维护成本高、逻辑变更频繁的旧宽表迁移至新的语义范式。这实现了平滑演进,而非颠覆式重建。

Q4: 指标平台如何支持现在流行的 AI 智能问数(ChatBI)?

混乱、非结构化的元数据是 AI 产生“幻觉”的根源。指标平台通过构建标准化的语义知识图谱(包含指标、维度、口径、血缘),为 AI 大模型提供了高质量的上下文。采用 NL2MQL2SQL 架构:用户自然语言提问 → LLM 生成基于语义知识的 MQL → 平台语义引擎将 MQL 翻译为精准、高效的 SQL → 智能路由至最优物化表或明细层执行 → 返回结果。这从根本上将 AI 生成 SQL 的“开放题”收敛为选择标准指标的“选择题”,实现高准确率。

Q5: 对于数字化初期的企业,直接建设统一指标平台是不是“杀鸡用牛刀”?

恰恰相反,这是实现 “数字化平权” 和弯道超车的战略机遇。传统企业经历了“先乱后治”的痛苦过程。数字化初期的企业可以直接采用最先进的“语义模型驱动”架构,跳过宽表泛滥、口径混乱的阶段,以较低门槛一步到位构建统一、敏捷、标准的数据服务能力,避免未来高昂的治理与重构成本。

Key Takeaways(核心要点)

  1. 指标混乱是“症”非“病”:它是传统烟囱式数据开发模式的必然产物,根源在于技术架构,而非管理能力。
  2. 治理需解耦逻辑与物理:有效的指标治理必须将业务语义的定义,从物理宽表的开发中解放出来。
  3. 统一语义层是核心:基于 NoETL 语义编织技术构建的统一指标平台,能够实现指标的“定义即开发、定义即服务”,成为企业唯一可信的数据事实源。
  4. 价值超越降本增效:除了提升开发效率、降低资源成本,更能保障决策一致性、赋能业务敏捷分析,并构成未来 AI 应用不可或缺的 AI-Ready 数据底座。
  5. 落地可渐进平滑:通过“存量挂载、增量原生、存量替旧”的三步走策略,企业可以在不影响现有业务的前提下,稳步向现代化数据架构演进。

**查看更多技术干货与产品详情,请访问Aloudata 官方技术博客,查看原文:https://ai.noetl.cn/knowledge-base/why-companies-have-hundred...

生成式 AI 的投资回报远超预期?Snowflake 调研全球 1900 位企业与 IT 专业人士后发现平均 ROI 高达 41%!点击下载完整报告

每个人都在努力提高大语言模型的精准度。但真正的挑战并非精度,而是上下文理解能力。在 BUILD 2025 大会上,Hex 合作伙伴工程负责人 Armin 探讨了为什么传统的方法,如评估套件或合成问题集往往不够有效,以及成功的 AI 系统是如何通过随着时间推移逐步积累上下文来构建的。

由 Snowflake Cortex 提供支持的 Hex,启用了一个新的对话式分析模型,每次交互都让模型变得更聪明。通过 Hex 的 Notebook Agent 与 Threads 功能,业务用户可直接定义核心问题,而数据团队则将这些问题精炼、审计并转化为持久且值得信赖的工作流。

在这个模型中,测试用例不再由数据团队闭门设计,而是由业务需求驱动并在数据工作流中自动实施,最终形成一个具有生命力的上下文系统,而非一成不变的提示词或测试集,它能随着组织共同演进。

准确率不是终点

Armin 开场就把矛头对准了一个常见做法:把业务用户会问的问题合成成一批样例,甚至进一步转成 SQL 查询,然后把这些喂给 LLM,用类似单元测试的方式去衡量它的准确率、稳定性与一致性。他不否认“准确性是顶层关注”,但他强调,把 LLM 当作传统软件组件来做单元测试,本身就是一个不合适的范式。

原因在于,当你把业务问题硬转换为一组 SQL,并据此去构建样例与评估集时,你很难覆盖真实业务中不断变化的语义、不断扩张的问题空间,以及不同用户在不同语境下对同一指标的不同问法。更重要的是,即使你做出了一个看似通过率很高的测试集,也依然回答不了企业最在意的那件事:当它在真实环境中生成了一个结论,你如何知道它不是在胡编?你又如何知道它到底做了什么才得到这个结论?

因此,Armin 把正确性从结果层拉回到系统层:你需要的不是一个靠样例证明自己正确的聊天机器人,而是一套可审计的系统,它能够随着时间变得灵活、可塑,能够让业务用户在使用中不断收敛可回答的问题类型,也能够让系统拥有被“硬化”的路径:哪些能力可以放开,哪些问题必须收紧,哪些定义需要固化,哪些数据应该进入上下文、哪些不应该。

在他看来,真正有效的路线是:从一套能运行、能被观察的系统出发,让系统在使用中暴露问题、沉淀模式,再反过来加固上下文。这种思路听起来不如直接做评估来得爽快,但它更接近企业系统的真实生长方式。

对话式分析如何变成“可审计的系统”

为了把“可审计”讲得具体,Armin 用 Hex 的产品演示展示了对话式分析在真实系统中应该是什么形态。演示从一个非常典型的业务问题开始:假设我是营销经理,我想让系统分析销售机会的“首次触达来源”(first touch source),并做营销归因视角的拆解。这里一个很关键的动作,是他先在系统里配置模型提供方:通过密钥对(key pair)连接到 Snowflake 实例,使用 Snowflake Cortex 内托管的 Claude,并强调这是一个“walled garden”的私有网络环境。这样做的直接意义是:模型驻留在数据所在的环境里,数据可以传递给模型,同时也能让 IT 团队对数据出入边界更放心。

进入线程后,Hex 并不是立刻吐出一句“结论”,而是在后台进行一系列用户不可见但决定可信度的步骤:它会先围绕可访问的元数据“思考”,查看平台上已有的 Hex 项目、仪表板或资产,判断是否存在可复用的内容;它会拉取来自数据仓库的表描述、列描述等元数据,并强调这些可以自动导入、不需要复杂配置;如果企业已经有 dbt 元数据,也可以进一步带入;随后它形成一个“漏斗式”的收敛过程:从广义元数据到相关表、再到更具体的模型信息与底层数据,最后才开始把 SQL 单元格、可能的 Python 单元格、图表与可视化逐步组织起来,用以回答最初的问题。

这也解释了他在演示里专门强调的一个点:这种模式一开始会“慢”,但这是刻意设计的。因为此时系统面对的是生产数据仓库,它需要把大量上下文带进来,需要推理与迭代,而这类深度思考天然会以时间为代价。换来的收益是:它可以生成更细致、接近数据科学家或嵌入式数据分析师水平的分析过程。Armin 也提到,未来会有更偏“快速、短促回答”的迭代版本,可能更多依赖语义模型,而不是每次都在全量上下文里深挖。但在这个阶段,他们优先解决的是“在没有分析师介入的情况下,业务用户也能得到一份扎实的分析报告”。

当线程生成结果后,界面里不仅有图表,还能继续做探索:拖拽维度与度量、查看底层表格数据、检查异常、做更深的切片。这时“可信度焦虑”就会自然出现:这么多信息暴露给业务用户,我怎么知道它没有幻觉?我该不该信这些 SQL?我如何让它更确定?Armin 的回答不是“相信模型”,而是把系统的底座亮出来:在 Hex 里,每一个线程、每一个项目,背后都由笔记本支撑。把线程保存为项目后,你可以在笔记本里看到完整对话以 Markdown 的形式呈现;更重要的是,你能看到它实际运行的 SQL、过滤条件、连接逻辑、图表生成过程,以及它如何一步步构建出整份报告。对于负责准确性与治理的数据团队来说,这种“把对话落到可审计的笔记本”非常关键——它让系统从一开始就具备被审核、被追责、被修正的可能。

在此基础上,Armin 进一步展示了一个更现实的协作场景:业务用户提出问题后,不一定要立刻去找数据团队提工单,而是先在对话线程里得到初步洞察;如果需要更深入的分析(比如进一步做季节性拆解),技术用户可以把笔记本智能体(notebook agent)限定在这个项目范围内,和智能体一起继续规划、推理、生成图表,并在生成的“待处理变更”中逐条审核、决定保留哪些结果。分析由此变成一种可协作、可迭代、可沉淀的工作流,而不是一次性、不可解释的问答。

从一次性对话到可复用资产

如果到这里为止,Hex 展示的是“可观察性”,那么 Armin 在后半段想讲的,是上下文如何变成系统能力,如何从一次性对话沉淀为可复用资产。

他先展示了一个从笔记本走向应用(app builder)的路径:当某些分析内容需要“持久化”,例如营销与销售负责人希望随时看到季节性分析或关键指标,而不是每次回来重新提问,那么就可以把笔记本中已经生成的图表、文本等资产拖拽到应用构建器里,做成一个仪表板、报告或更像 BI 的交互界面。这里的核心并不是“又做了一个 BI”,而是强调:即便呈现形态变成 BI 风格,背后依然由笔记本驱动,仍然保留 SQL、Python、Snowpark 等灵活性;同时,笔记本与应用这两种范式始终连接,资产是可回溯的。换句话说,展示层可以更友好,但底层逻辑并不会因此变成不可审计的黑箱。

紧接着他抛出了“连接胶水”的问题:当我们有线程、有笔记本、有应用,如何让它们构成一个一致的策略?答案是语义模型——它是 Armin 所谓“上下文引擎”的关键组成部分。原因也很务实:企业里那些精心构建的报表与仪表板,通常包含大量转化逻辑、业务口径、SQL/Python 查询,这些恰恰是 LLM 最需要、也最容易误解的上下文。如果不能把这些上下文结构化,LLM 的确定性就无从谈起。

在演示里,语义模型有两条路:一是导入已有的 Snowflake semantic view。Hex 可以浏览生产仓库、发现可访问的语义视图,然后快速引入,例如引入一个 B2B sales model,让 enriched metadata 直接在 Hex 中可用。另一条路更贴近多数团队的起点:不是先有语义视图,而是先有一堆被业务反复使用的仪表板项目。Hex 的语义建模工作台里有一个“建模智能体”(modeling agent),它能理解 Hex 的语义建模能力,并且能针对某个具体项目(例如 sales and marketing dashboard)去阅读项目里包含的 SQL 单元格、DataFrame 操作、joins、函数与过滤条件,形成建模计划,做错误预防,推断表关系,把“项目里已经存在的业务逻辑”烘焙进语义模型中。

这一段其实回答了一个关键的企业问题:语义模型从哪来?它不一定需要从零凭空设计,它可以从企业已经在用的分析资产中被抽取、被规范、被版本化。建好之后,语义模型还能用一种“拖拽式”的方式被检查:你可以选择维度、度量,查看聚合、查看系统生成的 SQL,在发布之前把模型硬化到你满意的程度。

更进一步,Armin 也回应了“供应商锁定”的担忧。他明确表示,Hex 不希望用专有 YAML 把用户锁死,并提到两个方向:其一是和 Snowflake 等一起推动“开放语义交换”(Open Semantic Interchange),一个由约 18 家甚至更多公司组成的联盟,目标是让语义模型信息能在不同系统之间互换,以促进 LLM 采用并避免 vendor lock-in;其二是更近期开启“写回”能力,让在 Hex 中构建的语义模型可以写回到 semantic views 中,保证不同系统间“友好共存”。这些内容在分享里出现得很明确:终点不是锁定格式,而是让用户愿意因为体验与工作流而持续使用。

当语义模型准备好后,线程侧的使用方式也随之变化:你可以把对话线程限定为“只使用语义模型”,而不是访问整个生产数据仓库。Armin 强调,这会让系统随着时间更确定:当你不断硬化语义模型、补充上下文,它会越来越稳定、越来越可控。也正因此,他再次回到开场的观点:把精力放在构建上下文系统上,而不是试图用合成样例把原型聊天机器人测到“看起来准确”。

规模化审计与上下文飞轮

分享的最后一部分,Armin 把问题推到最现实的规模化挑战上:当系统从一个人试用扩展到五十、一百个用户时,你如何监控它?你如何知道 LLM 系统到底在做什么,业务用户到底拿它解决什么问题?这时,“可审计”就不能停留在某个线程或某个项目,而必须成为一套能覆盖全局的治理能力。

他提到 Hex 的“上下文工作室”(context studio),目前处于少数 Alpha 合作伙伴的 Alpha 阶段,但他之所以专门强调它,是因为它承载了上下文系统最关键的一环:理解使用行为,反过来指导上下文如何演进。

具体来说,你可以看到平台总体使用情况:用户更常用笔记本还是线程?创建了多少语义模型?也可以按对话量看用户分布,查看某个用户使用线程的频次、提问的类型。更重要的是,当你下钻到“问题类型”时,Armin 给出了一个很强的判断:这些真实问题才是你的单元测试。不是你在上线前试图一次性“破坏一切”并用评估集兜住,而是看清业务用户到底在问什么,再回去硬化你需要硬化的上下文与问题类型。

围绕“如何策划上下文”,他在分享里给出了三个层次的抓手。最直接的是规则文件(rules file):你可以在里面定义 SQL 的数据质量防护、业务定义、偏好的 SQL 风格、杂项信息,以及希望系统使用的可视化方式,并且这些内容可以即时编辑、保存或导出。第二层是“经认可的数据”(endorsed data):由数据团队或所谓“金层”背书的数据资产,可以在 Hex 的语境下被定义清楚,决定哪些数据可以喂给 LLM。第三层则是更成熟、也最关键的做法:语义项目(semantic projects)。随着审计能力增强,你不仅能看到语义模型被使用的次数,还能观察是否有多个语义模型被同时使用、是否需要在某些场景中合并;你也能判断哪些项目最常被引用,从而决定是否需要对下游数据做更多建模,或者是否需要补充列描述、表描述等元数据来改善上下文质量。

这些细节共同指向同一个结论:上下文不是一次性设计出来的,它是被真实使用不断“磨”出来的。你从稍微宽的范围起步,抽取一两个语义模型,让业务用户用起来;再通过审计看到真实问题与真实路径,回去修规则、补语义、加背书数据、完善元数据。如此循环,系统才会越来越确定、越来越可信。

这场分享最有价值的地方,在于它没有把“可信”简化为一个指标,也没有把“准确率”当作唯一的归宿。Armin 反复强调的其实是另一套思维:企业要的不是一个在评估集上表现漂亮的聊天机器人,而是一套能持续吸收上下文、可审计、可治理的系统。

从线程到笔记本的可观察性,从笔记本到应用的资产化,从项目到语义模型的上下文结构化,再到面向规模化使用的审计与上下文工作室——这些环节被串成一个整体,目的只有一个:让 LLM 在真实业务里变得更确定,并且在需求增长时仍然能保持可控与可信。

原视频地址:https://www.snowflake.com/en/build/americas/agenda/?login=ML

🔥【活动推荐】2 月 2 日-6 日,Snowflake Discover重磅上线!这是一场免费、线上、可实时互动的技术活动,旨在帮助您全面提升数据与 AI 能力,深入了解如何更高效地管理、整合与分析数据。4 天时间 18 场技术干货分享,由来自亚太地区的一线技术专家亲自分享与讲解~

点击报名 Discover,更多 Snowflake 精彩活动请关注专区

原文链接:https://www.nocobase.com/cn/blog/weekly-updates-20260129

汇总一周产品更新日志,最新发布可以前往我们的博客查看

NocoBase 目前更新包括的版本更新包括三个分支:mainnextdevelop

version.png

main :截止目前最稳定的版本,推荐安装此版本。

next:包含即将发布的新功能,经过初步测试的版本,可能存在部分已知或未知问题。主要面向测试用户,用于收集反馈和进一步优化功能。适合愿意提前体验新功能并提供反馈的测试用户。

develop:开发中的版本,包含最新的功能代码,可能尚未完成或存在较多不稳定因素,主要用于内部开发和快速迭代。适合对产品功能前沿发展感兴趣的技术用户,但可能存在较多问题或不完整功能,不建议在生产环境中使用。

main

main.png

v1.9.40

发布时间:2026-01-25

🚀 优化

  • [Office 文件预览] 支持更多文件类型在微软在线预览工具中预览 (#8500) by @mytharcher

🐛 修复

  • [client]

    • 修复 nanoid 字段在表单提交后不重新生成数据的问题 (#8491) by @katherinehhh
    • 修复级联组件必填校验重复提示的问题 (#8476) by @katherinehhh
  • [database]

    • 修复数据表重载后使用 empty 操作符筛选报错的问题 (#8496) by @2013xile
    • 修复嵌套关联的深度更新问题 (#8492) by @chenos
  • [文件管理器] 修复上传文件时请求中的文件名被重复解码产生的乱码问题 (#8481) by @mytharcher
  • [数据源:主数据库] 修复在多对多关系表格区块中删除数据时,未遵循关系字段 onDelete: 'restrict' 约束的问题 (#8493) by @2013xile
  • [区块:iframe] 修复 Iframe 添加聚合变量报错的问题 (#8482) by @zhangzhonghe
  • [工作流:Webhook 触发器] 修复未配置请求体解析时触发器数据中该数据缺失的问题 by @mytharcher
  • [模板打印] 复了联合角色时打印按钮权限逻辑错误 by @jiannx
  • [工作流:审批]

    • 修复并发提交导致流程被重复恢复执行的问题 by @mytharcher
    • 修复分支模式的审批未能正确退回至指定节点的问题 by @mytharcher
  • [迁移管理] 修复迁移异常后打印异常对象所包含 SQL 过大容易卡死进程的问题 by @cgyrock

next

next.png

v2.0.0-beta.17

发布时间:2026-01-29

🐛 修复

  • [client] 修复筛选相关的已知问题 (#8514) by @zhangzhonghe
  • [AI 员工] 修复构建后系统无法启动问题 (#8523) by @cgyrock
  • [AI: 知识库] 修复构建后系统无法启动问题 by @cgyrock

v2.0.0-beta.16

发布时间:2026-01-27

🎉 新特性

  • [client] 新增子表格(弹窗编辑)字段组件 (#8280) by @katherinehhh
  • [工作流] 为移动节点增加 API (#8507) by @mytharcher

🚀 优化

  • [client]

    • 修复单元格更新导致表格整体重渲染 (#8349) by @katherinehhh
    • 改进对多子表单默认包含一个对象,无需点击 Add New,未填写时不创建记录 (#8458) by @katherinehhh
  • [文件管理器] 为文件管理器增加可扩展的预览组件 (#8501) by @mytharcher
  • [工作流] 修改工作流子页面的路由路径,将工作流页面都统一在 /admin/settings/workflow 路径之下 (#8519) by @mytharcher

🐛 修复

  • [client]

    • 修复筛选区块日期带时间时时间格式重复的问题 (#8506) by @zhangzhonghe
    • 修复多层级对多字段子表单字段联动规则无法使用表单变量赋值的问题。 (#8518) by @gchust
    • 修复多级弹窗及跨区块数据变更后不刷新问题。 (#8471) by @gchust
    • 修复编辑表单中配置阅读态子详情数据不能正常显示问题 (#8469) by @katherinehhh
    • 修复targetKey 可选字段的处理逻辑 (#8333) by @katherinehhh
    • 修复编辑态子表格中关系字段 Select 的 filter 参数错误问题 (#8335) by @katherinehhh
  • [flow-engine] 修复外部数据源 filterTargetKey 为单元素数组时 FilterByTK 处理错误 (#8522) by @katherinehhh
  • [AI 员工] 修复 AI 建模与数据源管理模块中可选字段配置不一致的问题 (#8488) by @cgyrock
  • [邮件管理] 选中文本时正文不折叠。修复附件下载失败 by @jiannx

v2.0.0-beta.15

发布时间:2026-01-25

🚀 优化

  • [Office 文件预览] 支持更多文件类型在微软在线预览工具中预览 (#8500) by @mytharcher

🐛 修复

  • [database] 修复数据表重载后使用 empty 操作符筛选报错的问题 (#8496) by @2013xile
  • [模板打印] 复了联合角色时打印按钮权限逻辑错误 by @jiannx
  • [工作流:审批] 修复 1.x 审批记录弹窗报错的问题 by @mytharcher
  • [迁移管理] 修复迁移异常后打印异常对象所包含sql过大容易卡死进程的问题 by @cgyrock

v2.0.0-beta.14

发布时间:2026-01-23

🎉 新特性

  • [AI 员工] AI 对话支持复制粘贴文件 (#8487) by @heziqiang

🚀 优化

  • [client]

    • 改进对多子表单默认包含一个对象,无需点击 Add New,未填写时不创建记录 (#8473) by @katherinehhh
    • 改进子表格中附件字段的上传与编辑按钮,引导用户点击上传 (#8474) by @katherinehhh
  • [flow-engine] 优化 runjs 的 ctx.libs, 使其支持按需加载,并新增 lodash, math, formula 预定义库。 (#8468) by @gchust
  • [错误处理器] 避免 SQL 引用错误直接暴露 (#8464) by @2013xile
  • [工作流:审批] 增加对 API 的访问控制,以避免通过 API 越权操作数据 by @mytharcher

🐛 修复

  • [client]

    • 修复富文本编辑器的弹出层被遮挡的问题 (#8443) by @zhangzhonghe
    • 修复筛选区块日期带时间时时间格式重复的问题 (#8484) by @zhangzhonghe
    • 修复 nanoid 字段在表单提交后不重新生成数据的问题 (#8491) by @katherinehhh
    • 修复级联组件必填校验重复提示的问题 (#8476) by @katherinehhh
    • filter列表去重 (#8431) by @jiannx
    • 修复在 Chrome 144 版本中不显示配置菜单的问题 (#8470) by @zhangzhonghe
  • [database]

    • 修复嵌套关联的深度更新问题 (#8492) by @chenos
  • [server] 修复通用依赖中 mathjs 包的版本 (#8475) by @mytharcher
  • [flow-engine] 修复内嵌弹窗页面连续打开联动规则配置和事件流配置后关闭弹窗报错的问题。 (#8368) by @gchust
  • [数据源:主数据库] 修复在多对多关系表格区块中删除数据时,未遵循关系字段 onDelete: 'restrict' 约束的问题 (#8493) by @2013xile
  • [异步任务管理器] 修复异步导入触发的工作流事件延迟执行的问题 (#8478) by @mytharcher
  • [区块:iframe] 修复 Iframe 添加聚合变量报错的问题 (#8482) by @zhangzhonghe
  • [UI 模板] 修复引用模板区块无法通过事件流设置数据范围的问题。 (#8472) by @gchust
  • [文件管理器] 修复上传文件时请求中的文件名被重复解码产生的乱码问题 (#8481) by @mytharcher
  • [操作:导入记录 Pro] 修复异步导入触发的工作流事件延迟执行的问题 by @mytharcher
  • [工作流:Webhook 触发器] 修复未配置请求体解析时触发器数据中该数据缺失的问题 by @mytharcher
  • [模板打印] 模板打印的配置模板弹窗移除底部按钮 by @katherinehhh
  • [工作流:审批]

    • 修复分支模式的审批未能正确退回至指定节点的问题 by @mytharcher
    • 修复并发提交导致流程被重复恢复执行的问题 by @mytharcher
    • 修复审批任务卡片字段不显示的问题 by @zhangzhonghe

develop

develop.png

v2.0.0-alpha.68

发布时间:2026-01-27

🎉 新特性

  • [工作流] 为移动节点增加 API (#8507) by @mytharcher

v2.0.0-alpha.67

发布时间:2026-01-26

🎉 新特性

  • [server] 重构应用监管器以适配不同场景下的多应用管理需求 (#8043) by @2013xile
  • [client] 新增子表格(弹窗编辑)字段组件 (#8280) by @katherinehhh
  • [AI 员工] AI 对话支持复制粘贴文件 (#8487) by @heziqiang

🚀 优化

  • [client]

    • 改进子表格中附件字段的上传与编辑按钮,引导用户点击上传 (#8474) by @katherinehhh
    • 改进对多子表单默认包含一个对象,无需点击 Add New,未填写时不创建记录 (#8473) by @katherinehhh
  • [flow-engine] 优化 runjs 的 ctx.libs, 使其支持按需加载,并新增 lodash, math, formula 预定义库。 (#8468) by @gchust
  • [server] 支持配置跨域 Origin 白名单 (#8454) by @2013xile
  • [文件管理器] 为文件管理器增加可扩展的预览组件 (#8501) by @mytharcher
  • [Office 文件预览] 支持更多文件类型在微软在线预览工具中预览 (#8500) by @mytharcher
  • [错误处理器] 避免 SQL 引用错误直接暴露 (#8464) by @2013xile
  • [操作:导出记录] 改进导出按钮数据范围:优先按选中记录,其次按前端筛选范围 (#8442) by @katherinehhh
  • [操作:导出记录 Pro] 改进导出按钮数据范围:优先按选中记录,其次按前端筛选范围 by @katherinehhh
  • [工作流:审批] 增加对 API 的访问控制,以避免通过 API 越权操作数据 by @mytharcher

🐛 修复

  • [client]

    • 修复筛选区块日期带时间时时间格式重复的问题 (#8484) by @zhangzhonghe
    • 修复 nanoid 字段在表单提交后不重新生成数据的问题 (#8491) by @katherinehhh
    • 修复富文本编辑器的弹出层被遮挡的问题 (#8443) by @zhangzhonghe
    • filter列表去重 (#8431) by @jiannx
    • 修复级联组件必填校验重复提示的问题 (#8476) by @katherinehhh
    • 修复在 Chrome 144 版本中不显示配置菜单的问题 (#8470) by @zhangzhonghe
    • 修复编辑表单中配置阅读态子详情数据不能正常显示问题 (#8469) by @katherinehhh
    • 修复自定义变量弹窗被遮挡的问题 (#8463) by @zhangzhonghe
    • 修复数据表字段分组排序设置不生效问题 (#8453) by @katherinehhh
    • 修复表格“列设置”按钮无效的问题 (#8441) by @zhangzhonghe
    • 修复关系文件快速编辑,选择文件的弹窗层级错误,无法保存弹窗配置的问题。 (#8446) by @gchust
    • 修复数据表图形界面编辑数据表报错问题 (#8451) by @katherinehhh
  • [database]

    • 修复数据表重载后使用 empty 操作符筛选报错的问题 (#8496) by @2013xile
    • 修复嵌套关联的深度更新问题 (#8492) by @chenos
  • [server] 修复通用依赖中 mathjs 包的版本 (#8475) by @mytharcher
  • [flow-engine]

    • 修复内嵌弹窗页面连续打开联动规则配置和事件流配置后关闭弹窗报错的问题。 (#8368) by @gchust
    • 修复能够重复点击配置菜单打开多个配置弹窗的问题。 (#8448) by @gchust
    • 修复 runjs 相关代码在运行前变量就被解析的问题。 (#8445) by @gchust
    • 修复数据选择器快速新增弹窗中无法选择弹窗变量的问题。 (#8450) by @gchust
  • [AI 员工] 修复 AI 建模与数据源管理模块中可选字段配置不一致的问题 (#8488) by @cgyrock
  • [数据源:主数据库] 修复在多对多关系表格区块中删除数据时,未遵循关系字段 onDelete: 'restrict' 约束的问题 (#8493) by @2013xile
  • [区块:iframe] 修复 Iframe 添加聚合变量报错的问题 (#8482) by @zhangzhonghe
  • [异步任务管理器] 修复异步导入触发的工作流事件延迟执行的问题 (#8478) by @mytharcher
  • [文件管理器] 修复上传文件时请求中的文件名被重复解码产生的乱码问题 (#8481) by @mytharcher
  • [UI 模板] 修复引用模板区块无法通过事件流设置数据范围的问题。 (#8472) by @gchust
  • [移动端(已废弃)] 弃用移动端插件(2.0 后将使用 ui-layout 插件代替) (#8456) by @chenos
  • [操作:导入记录 Pro] 修复异步导入触发的工作流事件延迟执行的问题 by @mytharcher
  • [工作流:Webhook 触发器] 修复未配置请求体解析时触发器数据中该数据缺失的问题 by @mytharcher
  • [模板打印]

    • 复了联合角色时打印按钮权限逻辑错误 by @jiannx
    • 模板打印的配置模板弹窗移除底部按钮 by @katherinehhh
  • [工作流:审批]

    • 修复审批任务卡片字段不显示的问题 by @zhangzhonghe
    • 修复分支模式的审批未能正确退回至指定节点的问题 by @mytharcher
    • 修复并发提交导致流程被重复恢复执行的问题 by @mytharcher
    • 修复 1.x 审批记录弹窗报错的问题 by @mytharcher
  • [邮件管理]

    • 修复邮箱配置弹窗被遮挡的问题 by @zhangzhonghe
    • 修复多个用户间相同邮箱邮件问题,性能优化 by @jiannx
  • [迁移管理] 修复迁移异常后打印异常对象所包含 SQL 过大容易卡死进程的问题 by @cgyrock

完全掌控,无限扩展,AI 协同。NocoBase 让你的团队快速响应变化,大幅降低成本。无需多年研发,无需数百万投入。花几分钟部署 NocoBase,立即拥有一切。

访问 NocoBase 官网

https://www.nocobase.com/cn

您可以在官网申请 Demo 演示,体验站点将在 1 分钟内创建完毕自动发送到您的邮箱。

访问 NocoBase GitHub 和 Gitee

https://github.com/nocobase/nocobase

https://gitee.com/nocobase/nocobase

下载 NocoBase 源码并安装。支持 Docker 安装、create-nocobase-app 安装和 Git 源码安装。

官方文档持续更新中

https://docs-cn.nocobase.com/

作者:傅榕锋,OceanBase 高级技术专家

AI 开发者需要什么样的数据库

在开始正式话题前,我们不妨先思考一个问题: AI 时代下开发者需要什么样的数据库?

自本世纪初以来数据库需求的演变历程。Web 2.0及业务在线化的时代,强调的是一个可靠、精确的记录系统,能够精准地记录每一笔交易数据,满足典型的事务处理(TP)需求。进入移动互联网和数据智能化时代后,随着数据量的爆发式增长,海量数据分析的需求成为主流。这时,分析型(AP)数据库开始占据重要位置。AI 时代的真正到来,驱动数据库不仅要支持查询和分析功能,更需具备理解和推理的能力。

快来关注我,获取 OceanBase 第一手的产品信息和技术资源,与行业大咖 “唠” 出真知!

AI 时代开发者的痛点

作为数据库从业者,我们需要深入分析 AI 时代下开发者对数据库的具体需求。

数据类型的多维化:在传统数据库中,图片、视频、音频仅能被存储而难以有效利用。借助 AI 模型的帮助,这些非结构化数据可以转化为可检索的形式,如通过嵌入模型转换为向量,或使用大语言模型提取文本描述和标签,从而将非结构化数据转变为结构化或半结构化数据以实现高效检索。

性能与规模的极致化:鉴于向量数据对内存和磁盘资源的高占用特性,在成本与性能之间寻求最佳平衡显得尤为关键。为此,亟需采用高效的算法,以优化召回率与资源成本之间的权衡关系。

智能处理的内生化:例如,在 RAG 场景中,文档需先进行切片并生成向量,这通常涉及向量数据库、文档型数据库以及事务型数据库的联合使用。为了简化这一流程,理想的解决方案是让数据库自身承担更多的标准化数据处理任务,减少开发者的负担。

开发流程的敏捷化:目标是让开发者更加专注于业务逻辑本身,而非陷入复杂的数据处理流程之中。

AI 时代的理想数据库

基于上述痛点,AI 时代的理想数据库应具备以下四个特征。

  • 多模态支持:提供统一的平台,支持多种数据类型,包括但不限于向量、全文、标量、 JSON 格式。
  • 高性能引擎:针对 AI 工作负载进行优化,确保在控制成本的前提下实现最优性能表现。
  • 智能化集成:内置 AI 运行时环境,使数据库可以直接执行复杂的智能处理任务,减少对外部系统的依赖。
  • 简易操作:设计直观易用的界面和工具,降低非专业开发者的使用门槛,促进更多领域专家参与到数据处理工作中。

综上所述, AI 时代我们期待的数据库应该是强大、智能、一体化的,是数据与 AI 融合的平台。

AI原生的一体化数据库是否存在

正所谓“需求决定市场”,契合AI时代理想数据库特质的产品必然会出现。而就目前来看,OceanBase 新发布的 seekdb 已率先落地,不仅具备了相关核心能力,更在快速迭代中持续进化。

混搜架构的轻量级、多模态的AI原生数据库

OceanBase seekdb 是一款面向 AI 场景的轻量级、多模态的原生数据库,专为支持混合搜索、上下文理解与智能数据处理而设计。其整体架构分为五个核心层级,实现从数据存储到查询执行的全链路优化。

1. 统一应用接口层。

seekdb提供基于 SQL 的统一查询语言,兼容标准 SQL 语法,支持多模态数据的联合查询。同时,提供面向开发者的 Python SDK,具备简洁易用的 API 接口,支持 skip-by-list 等高效检索模式,显著降低开发者使用门槛。

2. 支持混合负载的多模计算层。

继承自 OceanBase 的成熟优化器体系,seekdb具备强大的查询规划与执行能力,在混合检索场景中,会自动进行自适应执行和查询优化,能够根据查询条件自动选择最优执行路径。同时,支持混合负载自适应执行、AI 函数调用、ACID 事务保障及灵活 UDF 扩展,满足复杂业务需求。

3. 多模数据层。

支持多种数据类型统一存储,实现“存即能检”,打破传统系统中不同数据类型需分库管理的局限。包括:

  • 关系表(传统结构化数据)
  • 向量(Embedding 向量)
  • 文本(原始文本内容)
  • JSON(半结构化数据)
  • GIS(地理空间数据)
  • 数组、位图等扩展类型

4. 多模索引层。

构建业界领先的多模索引体系,支持的索引类型如下。

  • 向量索引:高效支持近邻搜索(ANN),兼顾精度与性能。
  • 全文索引:支持中文分词与语义匹配。
  • 混合索引:结合向量与标量条件进行联合检索。
  • JSON 索引:加速嵌套字段查询。
  • 二级索引、GIS 索引:满足多样化查询需求。

支持多索引协同查询,在一次请求中完成跨模态数据的融合检索。

5. 部署模式层。

  • 服务器模式:传统集群部署,适用于高并发、大规模生产环境。
  • 嵌入式模式:以库的形式内嵌于应用程序中,生命周期与应用一致,适合边缘计算、AI 应用快速构建等轻量化场景。

OceanBase seekdb 通过“统一接口 + 多模存储 + 智能索引 + 灵活部署”的一体化设计,实现了对 AI 工作负载的端到端支持,真正做到了“一个数据库,搞定所有数据”。

快速构建:更灵活、更轻量、不止于 SQL

OceanBase seekdb 不仅具备强大的功能,更在易用性和部署灵活性上进行了深度优化,助力开发者快速构建 AI 应用。

1. 更灵活:双运行模式,适配多样场景。

  • 服务器模式:适用于企业级、高可用、分布式部署。
  • 嵌入式模式:直接集成到 #Python 应用中,无需独立部署数据库服务,极大简化开发流程,特别适合 RAG、Agent、智能问答等轻量级 AI 应用。

2. 更轻量:极简资源占用,轻松跑起基准测试。

单实例仅需 1C2G 内存即可运行 VectorDBBench 基准测试,相比传统数据库,资源消耗更低,启动更快,非常适合本地调试、原型验证和边缘部署。

3. 不止于 SQL:引入 Schemaless SDK。

引入 Schemaless SDK,开发者无需定义表结构即可直接插入和查询数据,提升开发灵活性。

使用seekdb快速创建RAG应用

下面我们演示一下如何使用 seekdb 快使创建一个 RAG 应用。

第一步:三行代码快速创建一个知识库(SETUP)

  1. 导入 pyseekdb 模块,启用 seekdb 的 Python SDK。
  2. 初始化客户端实例,参数为空表示采用嵌入式模式,数据库生命周期与应用绑定,无需独立部署服务。
  3. 创建知识库并定义为 Collection。

第二步:批量插入文档片段(INSERT)

功能说明:

  • 调用 upsert() 函数批量插入文档内容(documents)。
  • 同时关联元数据(metadatas),包括分类、内存、存储、价格等结构化信息。
  • 显式指定文档 ID(ids),便于后续检索与更新。

关键特性:

  • 用户仅需提供原始文本和元数据,无需手动调用嵌入模型生成向量。
  • 数据库内部自动调用内置的嵌入模型,将文本转换为向量并存储。

AI 能力下沉至数据库,开发者无需关注向量化过程,seekdb 自动完成文本 → 向量的转换,实现“透明化”处理。

第三步:混合检索,精准召回(QUERY)

查询维度分析:

  • query_texts:输入自然语言文本,触发向量检索,用于语义匹配。
  • where:设置关系型过滤条件,如 category == laptop 和 ram >= 16,实现精确筛选。
  • where_document:基于全文索引进行关键词匹配,要求文档内容包含 “RAM”。
  • n_results:限制返回结果数量为 2 条。

实现机制:

  • 查询时,seekdb 内部自动将 query_texts 输入传递给嵌入模型,生成查询向量。
  • 结合向量索引、全文索引、二级索引等多种索引执行混合检索。
  • 最终返回满足所有条件的最相关结果。

第四步:效果展示

输入检索条件为:需要一个 12 GB 内存以上的高性能笔记本。运行后输出结果如下图所示,

召回结果分析如下。

  • 第一条:16GB 内存、512GB 固态的专业笔记本,完全满足“高性能 + 16GB 以上内存”的要求。
  • 第二条:32GB 内存、1TB 固态的游戏本,虽非专业用途但性能卓越,符合语义意图。

该案例模拟了典型的 RAG 场景,用户只需输入自然语言问题,系统即可自动完成文本向量化、多条件联合检索、高精度召回。全流程由数据库内核统一处理,极大简化了开发复杂度,真正实现“让开发者专注于业务,而非数据处理”。

欢迎亲自上手试用:https://github.com/oceanbase/seekdb。当前版本支持 Linux 平台下的嵌入式模式运行,Windows 和 macOS 版本将在近期和大家见面。可访问 oceanbase.ai 获取样例代码,支持本地测试与快速验证。

SQL 直接调用 AI 的原生体验

OceanBase seekdb 不仅是一个支持多模态数据存储与混合检索的数据库,更致力于将 AI 能力深度集成于数据库内核,实现“SQL 直接调用 AI”的原生体验。

seekdb AI Inside 的内置处理除了 AI_EMBED 方法外,还引入 AI_RERANK 和 AI_COMPLETE,可以实现数据分析自动化、特征提取、智能内容生成、语义搜索增强、结果优化等效果。在 seekdb 中使用可以构建从粗排到精排的高效分层混合检索处理流程。该流程分为四个阶段。

阶段1:标量过滤(Scalar Filtering)。在全量数据集上首先执行关系型条件过滤(如 category = 'laptop', ram >= 16),缩小候选集过滤范围。

阶段2:向量搜索(Vector Search)。对过滤后的候选集执行向量相似度检索,基于语义匹配找出最相关的文档,使用近邻搜索算法(ANN)高效完成高维向量比对。

阶段3:全文搜索(Full-text Search)。在候选集中进一步执行关键词匹配,确保结果包含用户关心的关键信息(如 "RAM"),支持中文分词与模糊匹配,提升召回精度。其中标量、向量、全文的过滤顺序取决于优化器。

阶段4:粗排 → 精排 → 大模型重排。经过以上过滤后得到粗排的结果,此时再去调用 AI_RERANK,数据库会直接调用 RERANK 模型进行精排,精排结束后,通过调用 AI_COMPLETE 即可调用大模型,大模型会直接进行回答。以上所有的 AI 标准操作流程都在数据库中进行,开发者只需在查询中添加相应函数,即可让数据库自动调用大模型对数据进行处理,显著提升用户体验。

OceanBase seekdb 适用场景

OceanBase seekdb 作为一款轻量级、多模态、AI 原生的数据库,凭借其统一存储、混合检索、内嵌 AI 能力 和嵌入式部署支持,在多个新兴与传统智能化场景中展现出显著优势。以下是其典型的适用场景。

1.替代“三库并行”,降本增效

在 RAG 架构中,传统方案通常需要同时维护三类数据库。

  • 向量数据库存储文本嵌入向量。
  • 文档数据库保存原始文本内容。
  • 关系型数据库管理元数据(如分类、时间、权限等)。

这种“三库并行”模式不仅带来高昂的运维复杂度,还导致资源重复占用(三份独立实例),难以在资源受限的本地或边缘环境中落地。seekdb 通过单一数据库统一承载向量、文本与结构化元数据,实现一次写入,多路索引(向量索引 + 全文索引 + 二级索引)、统一查询接口,支持混合条件过滤、极低资源开销(1C2G 即可运行),适合个人本地知识库、中小企业内部知识管理系统、边缘侧智能问答应用等。

2.语义搜索引擎,打破模态壁垒

seekdb 的多模态能力使其天然适配跨模态语义搜索场景。无论是文本、图片、音频还是视频,均可通过嵌入模型转化为统一的向量表示,并结合元数据进行联合检索,通过统一向量 + 元数据 + 全文的混合检索框架,打破模态壁垒。典型应用包括:以图搜图、音频内容检、视频片段语义匹配、多媒体资产管理系统。

3.Agentic AI 应用,保证数据一致性

在 Agentic AI(智能体)场景中,Agent 需要频繁执行上下文感知的混合检索,比如结合用户历史行为(标量过滤)、匹配任务目标语义(向量搜索)、检索相关文档片段(全文匹配)。seekdb 的原生混合检索引擎与内嵌 AI 函数能够高效支撑此类复杂查询,避免外部服务调用带来的延迟与一致性问题。适用于任务型对话系统、自主决策机器人、智能工作流引擎等应用场景。

4.AI 辅助编程,提升质量,降低成本

AI 编程助手存在云端 + 客户端双端检索需求,传统方案面临两大挑战。

  • 架构割裂:云端使用多源召回(向量+全文+语法树),客户端依赖轻量插件(如 SQLite + 向量扩展),两套系统逻辑不一致。
  • 性能瓶颈:通用数据库缺乏专业向量索引与优化器,召回效果与效率受限。

seekdb 提供统一的 SDK 与查询接口,可使云端与客户端使用同一套 API,且客户端在嵌入式模式下仍具备专业级向量检索能力。seekdb还支持代码语义搜索、API 推荐、错误修复建议等高级功能。通过这些能力统一技术栈,提升召回质量,降低双端开发与维护成本。

5.企业应用智能化丝滑升级

对于大量仍在使用 MySQL 的传统企业应用,seekdb 提供了一条平滑演进路径:

  • 高度兼容 MySQL 协议,现有应用可无缝迁移。
  • 迁移后即可获得 向量检索、全文搜索、JSON 支持等 AI 原生能力。
  • 为未来引入 RAG、智能报表、自动化分析等 AI 功能奠定数据基础。

因此,MySQL 到 OceanBase 的迁移是“最丝滑”的路径之一。seekdb 作为其轻量化延伸,进一步降低了企业智能化转型的技术门槛。

6.端侧应用智能化的理想选择

随着终端设备算力提升,越来越多智能应用向端侧迁移。seekdb 的嵌入式部署能力使其成为端侧智能数据库的理想选择:

  • 资源占用极低(1C2G 可运行)。
  • 支持离线向量检索与语义理解。
  • 生命周期与应用绑定,无需独立服务进程。
  • 让端侧应用具备“本地大脑”,减少对云服务的依赖。

典型场景包括:

  • 智能家居设备中的本地知识问答。
  • 工业机器人中的实时故障诊断。
  • 移动端个人助理的上下文记忆管理。
  • 车载系统的本地语义导航。

从轻到重、从简到繁: AI 应用快速迭代的理想基础设施

在 AI 应用快速迭代的背景下,开发者面临从原型验证、开发测试到生产部署的多阶段需求。OceanBase 与 seekdb 的深度融合,构建了一套覆盖全生命周期、支持平滑演进的弹性数据库架构,能够满足不同阶段、不同规模场景下的灵活部署需求。

原型验证与开发测试阶段:嵌入式模式(seekdb)

在项目初期,开发者通常需要快速验证 AI 模型效果或构建最小可行产品(MVP)。此时可采用 seekdb 嵌入式模式:

  • 将 libseekdb.so 动态库直接集成至应用中,作为本地数据库运行。
  • 数据库生命周期与应用绑定,启动即用,关闭即销毁。
  • 无需独立部署服务,极大简化环境搭建流程。
  • 支持向量、文本、JSON 等多模态数据存储与混合检索。

嵌入式模式适用于个人开发者快速原型开发、端侧智能应用(如移动端、机器人)、本地调试与算法验证等场景。

测试与小规模生产环境:单机部署模式

当应用进入测试或小规模上线阶段,可迁移到单机部署模式:

  • 启动独立的 seekdb 进程,提供服务端接口。
  • 支持多客户端连接,适合团队协作开发。
  • 可通过配置文件管理数据路径、内存参数等。
  • 仍保持与嵌入式模式的 API 兼容性,代码无需变更。

单机部署模式适用于小型工作负载、测试环境与生产环境、多租户需求等场景。

生产环境:多租户与高可用架构

随着业务稳定运行,需考虑资源隔离、高可用性和容灾能力,此时可选择以下两种生产级部署方式。

  • 单机多租户模式(OceanBase 单机部署) :

    • 使用 OceanBase 单机实例,通过多租户机制实现多个业务之间的资源隔离。
    • 适用于多个业务共享同一数据库实例但需独立管理资源的场景。
    • 支持独立的配额控制、备份策略和监控告警。
  • 主备模式 / 三副本模式(OceanBase 高可用架构):

    • 采用主备架构或三副本(2F1A)架构,保障数据高可用。
    • 支持自动故障切换与读写分离。
    • 适用于对稳定性要求较高的中小规模业务系统。

多租户与高可用架构适用于中小规模工作负载、对容灾和高可用有明确要求的业务、多租户共用数据库的 SaaS 平台等场景。

大规模与高性能场景:分布式集群架构

当业务持续增长,数据量和并发请求激增时,可进一步扩展为分布式集群架构。

  • 无共享分布式集群 :

    • 由多个 OBServer 节点组成,支持水平扩展。
    • 支持大规模工作负载、关键业务高并发访问。
    • 具备强一致性、线性可扩展性与动态扩容能力。
  • 基于对象存储的存算分离集群:

    • 存储层使用对象存储(如 OSS),计算层由 OBServer 提供。
    • 实现“冷热数据分离”,降低存储成本。
    • 适用于海量非敏感数据分析场景(如日志分析、历史归档)。
    • 提供更高的性价比与更强的扩展能力。

分布式集群架构适用于大规模工作负载、关键业务系统、高性能高并发、更高性价比的大数据处理任务等场景。

OceanBase 与 seekdb 的组合形成了一个 “从轻到重、从简到繁” 的完整弹性架构体系,核心优势有如下三点。

  • API 完全兼容:无论选择哪种部署模式,业务代码无需修改;
  • 配置驱动升级:只需更改连接地址与配置参数,即可完成架构迁移;
  • 平滑演进路径:支持从个人开发到企业级生产的无缝过渡。

这使得 OceanBase + seekdb 成为 AI 应用快速迭代的理想基础设施,真正实现了“一次开发,全栈适配”,助力企业在 AI 时代加速创新落地。

当然,在AI时代,AI数据库不足以支撑应用所需的完整基础设施能力,因此,OceanBase构建了上下文工程体系中的关键能力。让我们敬请期待下一篇文章。


MyBatis Dynamic SQL 是一种类型安全的 Java 领域特定语言(DSL),用于通过编程方式构建 SQL 查询,而非编写 SQL 字符串或基于 XML 的动态查询。它在运行时使用流畅的 Java 构建器生成 SQL,同时仍通过标准的 MyBatis 映射器执行。与手动拼接字符串或复杂的 XML 逻辑相比,这使得查询构建更安全、更易于重构,并且更不容易出错。

由于查询是用 Java 编写的,列名和表引用通过强类型的元数据类在编译时进行验证,这提供了更好的 IDE 支持并减少了运行时 SQL 错误。本文将解释 MyBatis Dynamic SQL,并展示如何在 Java 应用程序中使用它。

1. 使用 MyBatis Dynamic SQL 可以做什么?

MyBatis Dynamic SQL 支持大多数常见的 SQL 操作,包括 SELECTINSERTUPDATEDELETE,以及连接、子查询、分页、排序、条件过滤和批量操作。它允许我们逐步构建查询,仅在某些参数存在时添加条件,这使其成为搜索界面和过滤 API 的理想选择。

它直接与 MyBatis 映射器接口集成,意味着我们仍然可以受益于结果映射、事务处理和连接管理。由于它生成标准的 SQL,因此适用于 MyBatis 支持的任何数据库,没有供应商锁定的问题。

1.1 MyBatis Dynamic SQL 的工作原理

Dynamic SQL 基于两个组件:表元数据类和 DSL 构建器。元数据类用 Java 描述表和列。DSL 构建器使用这些类以流畅、类型安全的方式组装 SQL 语句。

DSL 不直接执行 SQL。相反,它生成语句提供者对象,例如 SelectStatementProviderInsertStatementProvider。这些对象被传递给使用 @SelectProvider@InsertProvider 及类似注解标注的映射器方法,然后 MyBatis 使用其正常的执行引擎来执行这些语句。

2. 项目设置与依赖

Maven 依赖

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.15</version>
</dependency>

<dependency>
    <groupId>org.mybatis.dynamic-sql</groupId>
    <artifactId>mybatis-dynamic-sql</artifactId>
    <version>1.5.2</version>
</dependency>

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.4.240</version>
    <scope>runtime</scope>
</dependency>

这些依赖项包括 MyBatis 本身、Dynamic SQL DSL 以及一个用于测试的嵌入式数据库。

注意
数据库驱动可以替换为 MySQL、PostgreSQL 或任何其他支持的数据库。MyBatis Dynamic SQL 不依赖于数据库类型,仅依赖于标准 SQL 生成。

数据库模式

schema.sql

CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    age INT
);

INSERT INTO users(username, email, age) VALUES
('thomas', 'thomas@jcg.com', 30),
('benjamin', 'benjamin@jcg.com', 22),
('charles', 'charles@jcg.com', 17);

此脚本创建一个简单的表并插入测试数据。内存中的 H2 数据库将在启动时执行此脚本,因此无需外部依赖即可测试查询。

领域模型

public class User {

    private Long id;
    private String username;
    private String email;
    private Integer age;

    // Getter 和 Setter 方法...
}

这个 POJO 代表数据库中的一行。MyBatis 会自动使用匹配的字段名将列映射到字段,因此本例不需要额外的结果映射。

3. 用于 Dynamic SQL 的表元数据

下面的类以类型安全的方式定义数据库表及其列,允许在构建查询时被 Dynamic SQL DSL 引用。它充当 Java 代码与实际数据库结构之间的桥梁,实现了列名和类型的编译时验证。

public final class UserDynamicSqlSupport {

    public static final User user = new User();

    public static final SqlColumn<Long> id = user.id;
    public static final SqlColumn<String> username = user.username;
    public static final SqlColumn<String> email = user.email;
    public static final SqlColumn<Integer> age = user.age;

    public static final class User extends SqlTable {

        public final SqlColumn<Long> id = column("id", JDBCType.BIGINT);
        public final SqlColumn<String> username = column("username", JDBCType.VARCHAR);
        public final SqlColumn<String> email = column("email", JDBCType.VARCHAR);
        public final SqlColumn<Integer> age = column("age", JDBCType.INTEGER);

        public User() {
            super("users");
        }
    }
}

这个类为 users 表定义了类型安全的元数据,使 MyBatis Dynamic SQL 可以在不使用原始 SQL 字符串的情况下构建查询。DSL 使用这些 Java 对象而非按名称引用列,从而提高了安全性和 IDE 支持。

内部类 User 继承 SqlTable,这将其标记为可用于 from(user) 和连接等子句的数据表。构造函数调用 super("users") 来告知 MyBatis 要在 SQL 语句(如 FROM users)中呈现的确切表名。

每个列都使用 SqlTable 中的 column() 方法定义,该方法注册列名及其 JDBC 类型。这会产生强类型的 SqlColumn<T> 对象,确保比较和条件在编译时使用正确的 Java 类型。

外部类公开了对表及其列的静态引用,以便于静态导入,使得查询读起来很自然,例如:select(id, username).from(user),同时保持完全的类型安全和重构友好。

映射器接口

@Mapper
public interface UserMapper {

    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
    List<User> selectMany(SelectStatementProvider selectStatement);
}

@Mapper 注解告诉 MyBatis 此接口应注册为映射器并在运行时进行代理。MyBatis 会自动生成实现,因此不需要具体的类。

selectMany 方法接受一个 SelectStatementProvider,它封装了完全呈现的 SQL 语句及其参数。MyBatis 执行该语句并将每个结果行映射到 User 对象,将它们作为 List<User> 返回。

@SelectProvider 注解指定 SQL 将由 MyBatis Dynamic SQL 的一部分 SqlProviderAdapter 动态提供。实际的 SQL 是在运行时从使用 DSL 构建的 SelectStatementProvider 生成的,而不是在注解或 XML 中编写 SQL。

4. 构建动态查询

在这里,我们使用流畅的 Dynamic SQL DSL 构建 SQL 语句,而不是编写原始 SQL 字符串。

public static void main(String[] args) throws Exception {

    MyBatisUtil.runSchema();

    try (SqlSession session = MyBatisUtil.getSession()) {

        UserMapper mapper = session.getMapper(UserMapper.class);

        SelectStatementProvider select
                = select(id, username, email, age)
                        .from(user)
                        .where(age, isGreaterThan(18))
                        .and(username, isLike("%tho%"))
                        .orderBy(username)
                        .build()
                        .render(RenderingStrategies.MYBATIS3);

        List<User> users = mapper.selectMany(select);

        users.forEach(u
                -> System.out.println(u.getUsername() + " - " + u.getAge()));
    }
}

此代码使用流畅的 Dynamic SQL DSL 动态构建一个 SELECT 查询,并将其渲染为与 MyBatis 兼容的语句提供者。通过以编程方式添加条件,它能够以类型安全且可维护的方式创建复杂的过滤器。在本例中,查询选择 age 大于 18 岁且 username 包含 "tho" 的用户,然后按用户名字母顺序对结果进行排序。

MyBatis 工具类

public class MyBatisUtil {

    private static SqlSessionFactory factory;

    static {
        try {
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            factory = new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static SqlSession getSession() {
        return factory.openSession(true);
    }

    public static void runSchema() throws IOException, SQLException {
        try (SqlSession session = getSession()) {
            Connection conn = session.getConnection();
            Statement stmt = conn.createStatement();

            try (InputStream is = Resources.getResourceAsStream("schema.sql")) {
                String sql = new String(is.readAllBytes(), StandardCharsets.UTF_8);
                stmt.execute(sql);
            }
        }
    }
}

此工具类加载 MyBatis 配置,构建 SqlSessionFactory,并提供对数据库会话的访问。它还通过执行 SQL 脚本(schema.sql)手动初始化数据库模式。

5. 使用 Dynamic SQL 进行插入、更新和删除

MyBatis 中的 Dynamic SQL 允许我们使用流畅的 DSL 以编程方式构造 INSERT、UPDATE 和 DELETE 语句。在此,我们演示如何执行这些常见的数据操作。

// INSERT
User newUser = new User();
newUser.setUsername("andrew");
newUser.setEmail("andrew@jcg.com");
newUser.setAge(28);

InsertStatementProvider<User> insert
        = insert(newUser)
                .into(user)
                .map(username).toProperty("username")
                .map(email).toProperty("email")
                .map(age).toProperty("age")
                .build()
                .render(RenderingStrategies.MYBATIS3);

int inserted = mapper.insert(insert);
System.out.println("Rows inserted: " + inserted);

// UPDATE
UpdateStatementProvider update
        = update(user)
                .set(age).equalTo(35)
                .where(username, isEqualTo("thomas"))
                .build()
                .render(RenderingStrategies.MYBATIS3);

int updated = mapper.update(update);
System.out.println("Rows updated: " + updated);

// DELETE
DeleteStatementProvider delete
        = deleteFrom(user)
                .where(age, isLessThan(18))
                .build()
                .render(RenderingStrategies.MYBATIS3);

int deleted = mapper.delete(delete);
System.out.println("Rows deleted: " + deleted);

相同的 DSL 风格也用于写操作。语句以流畅的方式构建、渲染,然后由映射器提供者方法执行。

  • INSERT:创建一个新的 User 对象并填充值。使用 Dynamic SQL DSL,我们将其字段映射到表列并生成 InsertStatementProvider。映射器执行插入操作,返回受影响的行数。
  • UPDATE:DSL 构建一个更新语句,将用户名为 "thomas" 的用户的年龄设置为 35。这确保只修改目标行,映射器执行更新。
  • DELETE:删除语句移除所有年龄小于 18 岁的用户。在 DSL 中使用条件保证了类型安全并避免了字符串拼接。

更新后的映射器接口

为了支持这些操作,映射器接口必须包含用于 INSERT、UPDATE 和 DELETE 的方法,使用 MyBatis Dynamic SQL 提供者。

// INSERT
@InsertProvider(type = SqlProviderAdapter.class, method = "insert")
int insert(InsertStatementProvider<User> insertStatement);

// UPDATE
@UpdateProvider(type = SqlProviderAdapter.class, method = "update")
int update(UpdateStatementProvider updateStatement);

// DELETE
@DeleteProvider(type = SqlProviderAdapter.class, method = "delete")
int delete(DeleteStatementProvider deleteStatement);

映射器中的每个方法处理一个特定的 DML 操作(插入、更新或删除),并接受一个封装了生成的 SQL 及其参数的 InsertStatementProviderUpdateStatementProviderDeleteStatementProvider。这种方法允许所有写操作都在 Java 中以编程方式表达,而无需手动组合 SQL 字符串,同时仍能利用 MyBatis 高效地执行语句和映射结果。

6. 结论

在本文中,我们探讨了如何在 Java 应用程序中使用 MyBatis Dynamic SQL 来创建类型安全、可维护且可编程的 SQL 查询。通过将 SQL 构建与执行分离,MyBatis Dynamic SQL 简化了复杂查询逻辑的处理,降低了错误风险,并提高了代码可读性。这种方法非常适合查询需要动态变化或经常修改的应用程序。

7. 下载源代码

本文讨论了 MyBatis Dynamic SQL 及其在 Java 中的使用方法。

下载

您可以通过此处下载此示例的完整源代码:java mybatis dynamic sql


【注】本文译自:Getting Started with MyBatis Dynamic SQL

在认知负荷极度饱和的数字化协作中,企业的效率瓶颈已从“数据获取”转向“关键信息的快速扫描与全局掌控”。平铺式信息展开工具不仅是静态的展示看板,更是通过横向铺展的视觉逻辑,将隐没在深层目录中的碎片化数据转化为可视化、可并行处理的平铺式智力资产的解析引擎。

一、 为什么现代决策必须重视“平铺式”展开?

传统层级化管理工具往往导致“信息遮蔽”:关键细节被掩盖在多级文件夹下,导致决策者难以在同一视域内完成信息的横向对比。平铺式信息展开工具的核心价值在于:

  • 消除视觉阻隔:通过将多源信息平铺于单一交互平面,确保每一个数据节点都能被即时观测,而非隐藏在点击之后。
  • 支撑高频扫描穿透:支持在展开过程中实现视角的平滑移动,从全局概览快速锁定至特定平面的执行细节。
  • 实现全景认知对齐:通过水平延展的逻辑结构,各模块的关联信息自动形成并列视图,确保团队对系统状态拥有无死角的同步感知。
  • 线性流向模块化展示:将复杂的业务长链条平铺为连续的视觉模块,实现跨阶段、跨单元的直观逻辑复核。

二、 平铺式展开的技术路径:全景视觉架构

构建平铺式信息展开体系需要遵循“空间释放”与“并列关联”的逻辑:

  1. 全景展示层(Panoramic Display):定义信息展开的水平边界,展示所有核心模块的并列排布关系。
  2. 平铺逻辑层(Flat Logic):将纵向深度转化为横向广度,记录各平铺单元间的流转路径与协作触点。
  3. 原子信息层(Atomic Info):位于平铺平面的最表层,聚焦于高价值数据的直接呈现,具备明确的视觉优先级标注。

三、 核心技术实现与算法示例

平铺式信息展开工具的底层逻辑涉及响应式布局计算、视口范围内渲染优化及平滑平移控制。

1. 基于视口检测的平铺单元延迟加载(JavaScript)

在海量信息平铺时,为保障性能,仅对视口内的单元进行渲染。以下为实现平铺节点动态加载的逻辑:

JavaScript

/**
* 检测平铺单元是否进入水平视口并触发加载
* @param {Element} unitNode 平铺单元节点
* @param {number} buffer 预加载缓冲区像素
*/
function handleFlatDisplay(unitNode, buffer \= 200) {

const rect \= unitNode.getBoundingClientRect();  
const isVisible \= rect.left \< (window.innerWidth \+ buffer) && rect.right \> \-buffer;

if (isVisible && \!unitNode.dataset.loaded) {  
    // 触发原子信息的平铺展开  
    loadAtomicData(unitNode);  
    unitNode.dataset.loaded \= "true";  
    console.log(\`\[Display Action\] 平铺单元 ${unitNode.id} 已进入视口并展开\`);  
}  

}

2. Python:信息铺展密度的动态优化引擎

利用平铺模型,自动检测视觉空间内的信息堆叠度,防止由于平铺过密导致的认知过载:

Python

class FlatDensityEngine:

def \_\_init\_\_(self):  
    \# 预设平铺标准:视域类型 \-\> 推荐展开间距与信息密度  
    self.density\_benchmarks \= {  
        "Executive\_Dashboard": {"min\_margin": 20, "max\_elements": 12},  
        "Task\_Flow": {"min\_margin": 10, "max\_elements": 25}  
    }

def verify\_flat\_efficiency(self, current\_layout, view\_type):  
    """对比实际铺展密度与标准,识别视觉疲劳风险"""  
    std \= self.density\_benchmarks.get(view\_type)  
    if not std:  
        return "未定义的平铺标准"

    element\_count \= len(current\_layout\['elements'\])  
    if element\_count \> std\['max\_elements'\]:  
        print(f"\[Visual Alert\] 信息铺展密度过高({element\_count}个节点),建议启用横向分页")  
        self.\_trigger\_layout\_optimization(current\_layout)

def \_trigger\_layout\_optimization(self, layout):  
    print(f" \-\> 已启动针对该平铺平面的空间重组建议")

3. SQL:跨平面信息关联度与扫描效率分析

通过数据查询,识别平铺平面中关联最紧密、扫描频率最高的“视觉热区”资产:

SQL

SELECT

view\_id,   
node\_name,   
horizontal\_position,   
AVG(scan\_duration) as scan\_efficiency  

FROM flat\_assets\_logs
WHERE layout\_type \= 'Tiled'
GROUP BY node\_name, view\_id
HAVING scan\_efficiency \< 2.5 -- 识别出用户能快速捕捉信息的平铺布局
ORDER BY scan\_efficiency ASC;


四、 工具分类与选型思路

实施平铺式信息展开时,工具的选择应基于对“横向延展力”的需求:

  • 全景白板类(如 FigJam/Miro):核心优势在于无限水平空间的自由铺展,支持将碎片信息通过物理平铺转化为直观的逻辑长卷。
  • 多列看板类(如 Trello/板栗看板):通过并列的列表实现信息的水平平铺,适合处理具有明确状态流转的并列事项。
  • 无限网格类(如 Airtable/Notion Gallery):利用网格视图实现元数据的平铺展示,适合对大量结构化对象进行视觉索引。

五、 实施中的风险控制与管理优化

  • 防止“空间迷失导致的扫描盲区”:应在工具中通过微缩全局地图(Minimap)或水平进度指示器,确保成员在横向漫游时仍具备全局观。
  • 动态收纳冗余平面:平铺不代表无限堆砌,应针对低频信息设置“折叠/展开”机制,保持核心平面的信息信噪比。
  • 定期进行视觉“清障”:随着任务推进,应移出已失效的平铺单元,确保视觉重心始终落在高优先级的执行流上。

六、 结语

平铺式展开是穿透复杂信息层级的有力手段。 它不仅解决了“关键信息被掩埋”的问题,更通过开阔的水平视觉架构,将企业的每一次数据沉淀转化为可以一览无余、极速扫描的执行场景。当组织的信息能够以平铺形式实现全景对齐时,团队才能在复杂的决策环境中实现“快速洞察”与“精准响应”的统一。

在节奏极快的敏捷协作中,企业的执行瓶颈已从“任务分配”转向“执行流的动态调整效率”。磁吸式事项排布工具不仅是灵活的看板,更是通过模拟物理磁性的自动吸附与排斥逻辑,将碎片化的任务转化为具备高度关联性、可自动纠偏的动态执行引擎。

一、 为什么现代敏捷团队必须重视“磁吸式”排布?

传统手动拖拽工具往往导致“排布松散”:任务间缺乏逻辑引力,计划变更时需要耗费大量人工进行二次对齐。磁吸式事项排布工具的核心价值在于:

  • 消除排程缝隙:通过事项间的“逻辑磁力”,确保每一个新插入的任务都能自动吸附至最合理的执行位点,消除时间线的无效空隙。
  • 支撑因果关联联动:支持事项间的强吸附特性,当上游节点移动时,下游依赖项如磁簇般自动跟随,维持逻辑链路的完整性。
  • 实现资源自动对齐:通过预设的属性引力(如成员、标签),相关事项会自动向特定资源池聚拢,显著降低人力分拨的认知成本。
  • 执行冲突自动排斥:当排布出现时间重叠或资源过载时,工具通过“磁极排斥”算法自动预警并推开冲突项,保持执行计划的物理可行性。

---

二、 磁吸式排布的技术路径:三维吸引力模型

构建磁吸式事项体系需要遵循“属性引力”与“逻辑约束”的原则:

  1. 引力锚点层(Gravity Anchor):定义排布的核心维度(如时间轴、项目阶段或负责人),作为事项吸附的基准。
  2. 磁极约束层(Polarity Constraint):设定事项间的吸引与排斥规则(如:前置任务吸引后置任务,同类资源相互吸附)。
  3. 状态感应层(Status Sensing):位于最底层,监控任务执行状态的变化,并实时触发位置重组。

---

三、 核心技术实现与算法示例

磁吸式排布工具的底层涉及向量位移计算、碰撞检测及引力场优化算法。

1. 基于模拟引力的事项自动对齐逻辑(JavaScript)

通过计算任务间的“逻辑距离”,实现事项在画布或列表上的自动吸附:

JavaScript

/**
* 计算事项节点间的磁吸位移
* @param {Object} taskA 核心任务节点
* @param {Object} taskB 待吸附任务节点
* @returns {Object} 建议的吸附坐标
*/
function calculateMagneticSnap(taskA, taskB) {

const threshold \= 50; // 磁吸感应阈值(像素)  
const deltaX \= Math.abs(taskA.endX \- taskB.startX);  
  
// 如果任务B的起点接近任务A的终点,则产生逻辑吸附  
if (deltaX \< threshold && taskB.dependencyId \=== taskA.id) {  
    console.log(\`\[Magnetic Snap\] 检测到逻辑引力,任务 ${taskB.name} 已吸附至 ${taskA.name}\`);  
    return {  
        newX: taskA.endX \+ 5, // 预留极小缓冲缝隙  
        snapped: true  
    };  
}  
return { snapped: false };  

}

2. Python:执行流冲突的“磁极排斥”审计引擎

利用物理碰撞模型,自动检测并弹开存在资源冲突的排布项:

Python

class PolarityAuditEngine:

def \_\_init\_\_(self):  
    \# 预设排斥标准:当同一负责人、时间重合度超过阈值时触发排斥  
    self.clash\_threshold \= 0.8 

def resolve\_overlap\_repulsion(self, schedule\_list):  
    """对比所有事项的时间区间,通过排斥力自动推开重叠项"""  
    for i, task\_a in enumerate(schedule\_list):  
        for task\_b in schedule\_list\[i+1:\]:  
            overlap \= self.\_calculate\_overlap(task\_a, task\_b)  
            if overlap \> self.clash\_threshold:  
                print(f"\[Polarity Alert\] 任务 '{task\_b\['name'\]}' 与 '{task\_a\['name'\]}' 存在磁性排斥(资源冲突)")  
                \# 触发自动位移推开逻辑  
                self.\_push\_away(task\_b, push\_distance=overlap \* 10)

def \_push\_away(self, task, push\_distance):  
    print(f"  \-\> 自动执行磁极排斥:任务计划向后顺延 {push\_distance} 单位时间")

3. SQL:高频磁吸关联项(执行簇)挖掘

通过统计任务间的关联频次,识别组织中最常协同出现的“磁吸任务簇”:

SQL

SELECT

t1.category AS node\_a,   
t2.category AS node\_b,   
COUNT(\*) AS attraction\_strength  

FROM tasks t1
JOIN tasks t2 ON t1.project\_id \= t2.project\_id
WHERE t1.id \!= t2.id
AND ABS(t1.completion\_time - t2.start\_time) \< '1 hour' -- 识别在时间上高度吸附的事项对
GROUP BY node\_a, node\_b
HAVING attraction\_strength \> 10 -- 识别出具备强磁性关联的任务模式
ORDER BY attraction\_strength DESC;

---

四、 工具分类与选型思路

实施磁吸式事项排布时,工具的选择应基于对“动态弹性”的需求:

  • 磁贴看板类(如 板栗看板/Trello 自动化插件):核心优势在于基于规则的自动移动,通过触发器实现卡片在列表间的自动跳转与吸附。
  • 弹性甘特图类(如 GanttPro/Instagantt):利用关键路径联动,实现事项在时间轴上的“磁力链”效应,适合强依赖性的工程项目。
  • 自由排布白板类(如 Muse/Milanote):支持在非线性空间内进行“磁吸分组”,适合创意策划等需要灵动排布的场景。

---

五、 实施中的风险控制与管理优化

  • 防止“磁力过载导致的排布震荡”:应避免过多的自动化触发链条,防止由于一个微小改动引发全量事项的剧烈位移。
  • 设置“手动锁定锚点”:针对关键的里程碑节点,应支持手动“消磁”锁定,防止其受周边事项调整的影响而发生位移。
  • 定期进行“磁场调优”:随着团队节奏变化,应重新定义事项间的引力规则,确保自动吸附的逻辑始终符合业务真实的紧迫程度。

---

六、 结语

磁吸式排布是驾驭执行变动性的敏捷盾牌。 它不仅解决了“排程死板”的问题,更通过灵活的物理化交互,将枯燥的任务清单转化为能够感知逻辑引力的生命体。当组织的事项能够实现自动化的引力对齐时,团队才能在瞬息万变的环境中,始终保持“有序排布”与“即时响应”的动态平衡。

在认知负荷极度饱和的数字化协作中,企业的效率瓶颈已从“数据获取”转向“结构化关系的精准解析”。嵌套式结构映射工具不仅是静态的关系图谱,更是通过多维拓扑的逻辑映射,将错综复杂的业务网络转化为可视化、可横向/纵向关联的嵌套式语义资产的解析引擎。

一、 为什么现代决策必须重视“嵌套式”映射?

传统单层思维导图或线性列表往往导致“语义孤岛”:关联关系被割裂,底层逻辑被掩盖在离散的节点中。嵌套式结构映射工具的核心价值在于:

  • 消除认知盲区:通过节点内部的无限嵌套,确保每一个细微变量都能在宏观结构中找到归属,而非悬浮存在。
  • 支撑多维关联穿透:支持在映射过程中实现跨层级穿透,从核心业务逻辑层瞬移至最边缘的支撑细节。
  • 实现拓扑知识对齐:通过多重包含关系,各模块的映射逻辑自动形成互联网络,确保团队对复杂系统认知的一致性。
  • 非线性问题模块化封装:将已验证的结构模型封装为嵌套组件,实现复杂方案在不同业务场景下的快速映射与调用。

---

二、 嵌套式映射的技术路径:三维拓扑架构

构建嵌套式结构映射体系需要遵循“节点解构”与“映射关联”的逻辑:

  1. 宏观拓扑层(Macro Topology):定义映射的核心锚点,展示业务全局的价值流向、核心约束及系统边界。
  2. 嵌套关联层(Nested Relation):将核心节点拆解为具有从属或并列关系的二级映射空间,记录节点间的动态交互与因果链条。
  3. 元数据映射层(Metadata Mapping):位于映射的最深处,聚焦于具体数据的定义与参数,提供原子级的属性描述与验证标准。

---

三、 核心技术实现与算法示例

嵌套式结构映射工具的底层逻辑涉及节点深度遍历、环路一致性检测及关联路径优化算法。

1. 基于递归搜索的嵌套节点搜索(JavaScript)

在嵌套结构中,快速定位深层节点是映射的核心。以下为实现节点深度检索的逻辑:

JavaScript

/**
* 递归检索嵌套映射结构中的目标节点
* @param {Array} mapNodes 映射节点数组
* @param {string} targetId 目标节点ID
* @returns {Object|null} 匹配到的嵌套节点对象
*/
function findNestedNode(mapNodes, targetId) {

for (const node of mapNodes) {  
    if (node.id \=== targetId) return node;  
      
    // 如果存在嵌套子层级,则继续向下递归检索  
    if (node.nestedLayers && node.nestedLayers.length \> 0) {  
        const found \= findNestedNode(node.nestedLayers, targetId);  
        if (found) return found;  
    }  
}  
return null;  

}

2. Python:映射结构冗余度动态审计引擎

利用嵌套模型,自动检测节点间的重复映射与过度嵌套,识别认知冗余风险:

Python

class MappingAuditEngine:

def \_\_init\_\_(self):  
    \# 预设映射标准:节点类型 \-\> 推荐嵌套深度与关联密度  
    self.mapping\_benchmarks \= {  
        "Logic\_Flow": {"max\_depth": 5, "avg\_links": 3},  
        "Data\_Model": {"max\_depth": 3, "avg\_links": 8}  
    }

def verify\_mapping\_efficiency(self, current\_map, map\_type):  
    """对比实际嵌套深度与标准,识别冗余或过于复杂的映射点"""  
    std \= self.mapping\_benchmarks.get(map\_type)  
    if not std:  
        return "未定义的映射标准"

    actual\_depth \= self.\_get\_max\_depth(current\_map)  
    if actual\_depth \> std\['max\_depth'\]:  
        print(f"\[Map Alert\] 嵌套深度达 {actual\_depth} 层,已超出认知负荷阈值")  
        self.\_suggest\_flattening(current\_map)

def \_get\_max\_depth(self, node, level=1):  
    if not node.get('children'):  
        return level  
    return max(self.\_get\_max\_depth(c, level \+ 1) for c in node\['children'\])

3. SQL:嵌套节点关联路径与影响力分析

通过递归公用表表达式(CTE),查询特定节点在整个嵌套网络中的波及范围:

SQL

WITH RECURSIVE NodeImpactPath AS (

\-- 起始:选择目标嵌套节点  
SELECT id, node\_name, parent\_id, 1 AS impact\_level  
FROM map\_nodes WHERE id \= 'target\_node\_001'  
UNION ALL  
\-- 递归:向上或向下追踪所有受影响的嵌套关联单元  
SELECT mn.id, mn.node\_name, mn.parent\_id, nip.impact\_level \+ 1  
FROM map\_nodes mn  
INNER JOIN NodeImpactPath nip ON mn.parent\_id \= nip.id  

)
SELECT

node\_name,   
impact\_level,  
COUNT(\*) OVER() as total\_affected\_nodes  

FROM NodeImpactPath
ORDER BY impact\_level ASC;

---

四、 工具分类与选型思路

实施嵌套式结构映射时,工具的选择应基于对“空间展开能力”的需求:

  • 无限卡片嵌套类(如 Miro/板栗看板):核心优势在于白板级的自由嵌套与视觉连通,支持将映射逻辑转化为直观的视觉卡片。
  • 关系型图谱类(如 Obsidian/Logseq):通过双向链接构建隐性的嵌套结构,适合处理非线性、网状演化的知识体系。
  • 结构化映射类(如 MindManager/XMind):经典的层级嵌套工具,适合对业务流程、组织架构进行强逻辑性的垂直映射。

---

五、 实施中的风险控制与管理优化

  • 防止“无限嵌套导致的黑洞效应”:应设定合理的嵌套阈值(如不超过 7 层),并在工具中利用“缩放语义(Semantic Zooming)”技术,确保在高倍率缩放时仍能识别核心节点。
  • 动态同步映射资产:嵌套节点应具备实时更新能力,当底层数据发生变动时,高层嵌套结构的映射逻辑需自动完成一致性校验。
  • 定期进行结构“修剪”:随着映射逻辑的成熟,应合并相似的嵌套层级,保持映射图谱的清晰度与决策支持效能。

---

六、 结语

嵌套式结构映射是解析系统复杂性的手术刀。 它不仅解决了“关系散乱”的问题,更通过精密的多维结构,将企业零散的认知片段转化为具备高度逻辑自洽性的智能资产。当组织的思维能够以嵌套形式实现水平与垂直的完美对齐时,团队方能在剧烈的市场波动中实现“全局洞察”与“精准打击”的统一。

熟悉 Spring Boot 3 的开发者,都知道它在简化开发流程、提高开发效率方面的出色表现吧!但是,在实际业务场景中,大家肯定都碰到过这样的棘手问题:订单数据存放在 MySQL 里,库存数据在 PostgreSQL 中,用户数据又保存在 MongoDB 中,当多种数据源同时存在时,想要实现统一查询简直比登天还难。

所以呢,今天我就亮出我的“终极大招”——Apache Calcite,着重给大家讲讲它怎样与 Spring Boot 3 实现无缝集成,还会分享一些可以直接拿来使用的经典应用场景。掌握了这一招,多数据源查询的难题就能轻松解决啦!

一、核心认知:Apache Calcite 为何是多数据源查询的利器?

在动手集成前,咱们先把核心逻辑搞明白:为啥 Calcite 能成为多数据源查询的“万能钥匙”?它的核心优势到底在哪?

1.1 不止是查询引擎:Calcite 的核心定位

Apache Calcite 本质是一个动态数据管理框架,而非传统的数据库。它最核心的价值在于“解耦”——将数据存储与数据查询分离,无论数据存在哪里、是什么格式,都能通过统一的 SQL 接口进行查询。

说通俗点,Calcite 就像个“超级数据翻译官”——不管数据藏在哪个数据源里、是什么格式,你只要写一套标准 SQL,它就能翻译成对应数据源能懂的指令,最后把结果整理成统一格式返回。这也是它能搞定多数据源查询的核心秘诀!

1.2 Calcite 的核心能力拆解

统一 SQL 接口:支持标准 SQL,无论底层是关系型数据库(MySQL、PostgreSQL)、非关系型数据库(MongoDB、Redis),还是文件(CSV、Parquet)、大数据引擎(Hive、Spark),都能通过同一套 SQL 查询。

  1. 强大的查询优化:内置基于规则和成本的查询优化器,能自动优化 SQL 执行计划,提升查询效率,尤其是在复杂多表关联、跨数据源查询场景下,优化效果明显。
  2. 灵活的数据源适配:通过“适配器(Adapter)”机制适配不同数据源,社区已提供大量现成适配器,也支持自定义开发,适配特殊数据源。
  3. 轻量级集成:核心依赖体积小,无复杂依赖,可轻松集成到 Spring Boot、Spring Cloud 等主流 Java 开发框架中,无需单独部署独立服务(也支持独立部署)。

    二、重点实战:Spring Boot 3 集成 Calcite 核心步骤

    既然大家都熟悉 Spring Boot 3 的基础操作,我就不啰嗦项目搭建这些常规步骤了,直接聚焦 Calcite 集成的核心环节,每一步都附完整代码和避坑提醒,跟着做就能成!

2.1 核心依赖引入

第一步先引依赖,在 pom.xml 里加好 Calcite 核心包、对应数据源的适配器,再配上 MyBatis Plus 的核心依赖(替换掉原来的 Jdbc 依赖就行),具体如下:

<!-- Calcite 核心依赖 -->
<dependency>
    <groupId>org.apache.calcite</groupId>
    <artifactId>calcite-core</artifactId>
    <version>1.36.0</version> 
</dependency>

<!-- MySQL 适配器(用于适配 MySQL 数据源) -->
<dependency>
    <groupId>org.apache.calcite</groupId>
    <artifactId>calcite-mysql</artifactId>
    <version>1.36.0</version>
</dependency>

<!-- MongoDB 适配器(用于适配 MongoDB 数据源) -->
<dependency>
    <groupId>org.apache.calcite</groupId>
    <artifactId>calcite-mongodb</artifactId>
    <version>1.36.0</version>
</dependency>

<!-- Spring Boot 与 MyBatis Plus 集成核心依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.5</version> <!-- 适配 Spring Boot 3 的稳定版 -->
</dependency>

<!-- 数据库连接池依赖(MyBatis Plus 需连接池支持) -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.20</version>
</dependency>

这里有 3 个避坑点必须强调下:

  1. Calcite 所有组件版本要统一,不然容易出现类加载异常;
  2. MyBatis Plus 得选适配 Spring Boot 3 的版本(3.5.3+);
  3. 一定要加连接池依赖,不然 Calcite 数据源没法被 MyBatis Plus 正常管理。

    2.2 核心配置:Calcite 模型文件编写

    模型文件是 Calcite 识别数据源的关键,一般用 JSON 格式,放在 resources 目录下命名为 calcite-model.json 就行。下面给大家一个适配 MySQL 和 MongoDB 双数据源的示例,直接改改连接信息就能用:

{
  "version": "1.0",
  "defaultSchema": "ecommerce",
  "schemas": [
    {
      "name": "ecommerce",
      "type": "custom",
      "factory": "org.apache.calcite.adapter.jdbc.JdbcSchema$Factory",
      "operand": {
        "jdbcUrl": "jdbc:mysql://localhost:3306/ecommerce_order?useSSL=false&serverTimezone=UTC",
        "username": "root",
        "password": "123456",
        "driver": "com.mysql.cj.jdbc.Driver"
      }
    },
    {
      "name": "user_mongo",
      "type": "custom",
      "factory": "org.apache.calcite.adapter.mongodb.MongoSchema$Factory",
      "operand": {
        "host": "localhost",
        "port": 27017,
        "database": "user_db",
        "collection": "user_info"
      }
    }
  ]
}

几个关键配置给大家解释清楚,避免踩坑:

  1. defaultSchema:默认查询的 Schema,可省略,查询时需指定 Schema 名称(如 ecommerce.order、user_mongo.user_info)。
  2. factory:对应数据源的适配器工厂类,Calcite 已为主流数据源提供现成工厂,自定义数据源需实现自己的 Factory。
  3. operand:数据源连接参数,根据数据源类型不同配置不同参数(如 MySQL 的 jdbcUrl、MongoDB 的 host/port)。

    2.3 Spring Boot 集成 Calcite + MyBatis Plus 核心配置

    这一步是核心,主要分两步走:

    配置好 Calcite 数据源;
    让 MyBatis Plus 用上这个数据源,顺便把 mapper 扫描、分页插件这些基础参数配好。直接上配置类代码:

    import com.baomidou.mybatisplus.annotation.DbType;
    import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.apache.calcite.jdbc.CalciteConnection;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.util.Properties;
    
    @Configuration
    // MyBatis Plus  mapper 接口扫描(指定 mapper 包路径)
    @MapperScan(basePackages = "com.example.calcite.mapper")
    public class CalciteMybatisPlusConfig {
    
     // 1. 配置 Calcite 数据源(核心,与原逻辑一致)
     @Bean
     public DataSource calciteDataSource() throws Exception {
         Properties props = new Properties();
         props.setProperty("model", "classpath:calcite-model.json");
         Connection connection = DriverManager.getConnection("jdbc:calcite:", props);
         CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class);
         return calciteConnection.getDataSource();
     }
    
     // 2. 配置 MyBatis Plus 的 SqlSessionFactory,指定使用 Calcite 数据源
     @Bean
     public SqlSessionFactory sqlSessionFactory(DataSource calciteDataSource) throws Exception {
         MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
         // 注入 Calcite 数据源
         sessionFactory.setDataSource(calciteDataSource);
         // 配置 mapper.xml 文件路径(如果使用 XML 方式编写 SQL)
         sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                 .getResources("classpath:mapper/*.xml"));
         // 配置 MyBatis Plus 全局参数(可选)
         org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
         configuration.setMapUnderscoreToCamelCase(true); // 下划线转驼峰
         sessionFactory.setConfiguration(configuration);
         // 注入 MyBatis Plus 插件(如分页插件)
         sessionFactory.setPlugins(mybatisPlusInterceptor());
         return sessionFactory.getObject();
     }
    
     // 3. MyBatis Plus 分页插件(可选,复杂查询分页用)
     @Bean
     public MybatisPlusInterceptor mybatisPlusInterceptor() {
         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
         interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 适配 Calcite 兼容的 MySQL 语法
         return interceptor;
     }
    
     // 4. 配置事务管理器(可选,需要事务支持时添加)
     @Bean
     public PlatformTransactionManager transactionManager(DataSource calciteDataSource) {
         return new DataSourceTransactionManager(calciteDataSource);
     }
    }

    核心逻辑给大家捋一捋:先通过 Calcite 创建统一的数据源,再把它注入到 MyBatis Plus 的 SqlSessionFactory 里。这样一来,咱们后续写代码就完全是 MyBatis Plus 的熟悉风格了,不管是 Mapper 接口还是 XML 映射文件,都能直接用,跨数据源查询的复杂逻辑全交给 Calcite 处理。

2.4 核心查询实现(MyBatis Plus 风格)

接下来就是大家最熟悉的查询实现环节了,我用 MyBatis Plus 最常用的“Mapper 接口+注解”和“XML”两种方式来演示,还是以 MySQL 订单表和 MongoDB 用户表的关联查询为例,大家可以根据自己的习惯选:

(1)定义实体类(对应跨数据源查询结果,可使用 lombok 简化代码)

import lombok.Data;

@Data
public class UserOrderVO {
    private String orderId;      // 订单 ID(来自 MySQL)
    private String orderTime;    // 下单时间(来自 MySQL)
    private BigDecimal amount;   // 订单金额(来自 MySQL)
    private String userName;     // 用户名(来自 MongoDB)
    private String phone;        // 手机号(来自 MongoDB)
    private String userId;       // 用户 ID(关联字段)
}

(2)定义 Mapper 接口(MyBatis Plus 风格,无需编写实现类)

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;

// 继承 BaseMapper,获得 MyBatis Plus 基础 CRUD 能力
public interface UserOrderMapper extends BaseMapper<UserOrderVO> {
    // 注解方式编写跨数据源关联 SQL
    @Select("SELECT " +
            "o.order_id AS orderId, o.order_time AS orderTime, o.amount, " +
            "u.user_name AS userName, u.phone, o.user_id AS userId " +
            "FROM ecommerce.order o " +  // ecommerce:MySQL 的 Schema;order:订单表
            "JOIN user_mongo.user_info u " +  // user_mongo:MongoDB 的 Schema;user_info:用户表
            "ON o.user_id = u.user_id " +
            "WHERE o.user_id = #{userId}")
    List<UserOrderVO> queryUserOrderByUserId(@Param("userId") String userId);

}

(3)编写 Service 层

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserOrderServiceImpl extends ServiceImpl<UserOrderMapper, UserOrderVO> implements UserOrderService {
    @Override
    public List<UserOrderVO> getUserOrderByUserId(String userId) {
        // 调用 Mapper 接口方法,实现跨数据源查询
        return baseMapper.queryUserOrderByUserId(userId);
        // 若使用 XML 方式:return baseMapper.queryUserOrderByUserIdWithXml(userId);
    }
}

(4)编写 Controller 层

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class CrossDataSourceQueryController {
    @Autowired
    private UserOrderService userOrderService;

    @GetMapping("/user/order/{userId}")
    public List<UserOrderVO> queryUserOrder(@PathVariable String userId) {
        // 调用 Service 方法,返回跨数据源查询结果
        return userOrderService.getUserOrderByUserId(userId);
    }
}

最后再划 3 个重点,确保大家少走弯路:

  1. 实体类字段要和查询结果列名对应,用别名适配下划线转驼峰更省心;
  2. Mapper 接口继承 BaseMapper 后,MyBatis Plus 的分页、条件构造器这些功能都能直接用,复杂查询也能轻松搞定;
  3. 咱们写的都是标准 SQL,Calcite 会自动解析适配不同数据源,完全不影响大家原来的开发习惯。

    三、深度解析:Calcite 的经典使用场景

    讲完了集成步骤,再跟大家深度拆解下 Calcite 的经典落地场景。毕竟技术最终要服务于业务,这些场景都是我在实际项目中常用到的,拿来就能用!

第一个经典场景是多系统数据融合查询,这也是企业级中台的核心需求。做企业级中台的小伙伴肯定深有体会,大型企业里数据都是分散的——订单系统用 MySQL,用户系统用 MongoDB 存行为数据,库存系统用 PostgreSQL。要是想做“用户-订单-库存”全链路分析,传统做法得分别调三个系统的接口,再在业务层手动整合数据,不仅效率低,还容易出错。用 Calcite 分别适配这三个数据源后,只要写一套标准 SQL 就能实现跨数据源关联查询,咱们用 Spring Boot 3 搭好接口服务,业务层完全不用管数据存在哪,专注核心业务逻辑就行,亲测开发效率能提升 50%以上,再也不用写重复的接口调用和数据整合代码,而且 Calcite 的查询优化器会自动优化关联逻辑,查询效率也能跟上。

第二个场景是实时数据与离线数据联动查询,做电商的小伙伴应该经常遇到这类需求。比如实时订单数据存在 Kafka 里,历史订单数据存在 Hive 里,运营需要实时查看“今日订单+近 30 天历史订单”的汇总数据来做实时监控和决策。这种情况不用麻烦地把 Kafka 数据同步到 Hive,也不用把 Hive 数据同步到实时库,直接用 Calcite 的 Kafka 适配器(calcite-kafka)和 Hive 适配器(calcite-hive),就能把实时流数据和离线数据放到同一个查询体系里,写一条 SQL 就能实现“实时+离线”数据的联合查询,既省了大量数据同步成本,又能兼顾实时性和准确性,还支持增量查询。

第三个场景是自定义数据源适配,主要解决特殊格式数据查询的难题。企业里总有很多 CSV、Excel、Parquet 格式的文件数据,传统做法是先把这些文件导入数据库才能查询,步骤又多又耗时,尤其是临时做数据分析的时候,导入数据库的成本太高了。而 Calcite 内置了文件适配器(calcite-file),支持直接查询这些文件数据,根本不用导入数据库。咱们再结合 Spring Boot 3 的文件上传功能,还能实现“文件上传后直接用 SQL 查询”的需求,临时分析数据超方便。如果有企业内部的特殊格式文件,比如自定义的二进制文件,也可以自己实现 Calcite 的 SchemaFactory 和 TableFactory 接口,写个自定义适配器,就能适配这些特殊数据源了。

四、避坑指南:集成注意事项与优化建议

4.1 这些坑一定要避开!

  • 适配器版本要统一:Calcite 核心依赖和各数据源适配器的版本必须一致,不然很容易出现类加载异常,这个坑我踩过,大家一定要注意。
  • 模型文件配置要规范:Schema 名称、表名要清晰,别重复;数据源的地址、端口、账号密码这些连接参数一定要准确,错一个就会连接失败。
  • 要考虑数据源性能:跨数据源查询的性能取决于最慢的那个数据源,所以要确保每个数据源自身性能没问题,不然会拖慢整个查询。

    4.2 优化小技巧,查询更快更稳

  • 启用 Calcite 缓存:配置一下 Calcite 的元数据缓存和查询计划缓存,能减少重复解析和元数据查询的时间,提升查询效率。
  • 优化 SQL 写法:尽量避免复杂的多表关联,能把过滤条件下推到数据源的就尽量下推。虽然 Calcite 会自动优化,但手动优化后的效果会更好。
  • 自定义优化规则:如果是特别复杂的业务场景,可以自己实现 Calcite 的 OptimizerRule 接口,写自定义的查询优化规则,进一步提升查询效率。

    五、本文总结

    最后总结一下,对于熟悉 Spring Boot 3 的咱们来说,集成 Calcite 的关键就是理解它“统一查询”的核心思想,把模型文件写对、核心 Bean 配置好,就能快速实现多数据源查询能力了。https://mybj123.com/28732.html

生成式 AI 的投资回报远超预期?Snowflake 调研全球 1900 位企业与 IT 专业人士后发现平均 ROI 高达 41%!点击下载完整报告

在当今竞争激烈的电商领域,为客户提供个性化体验已不再是奢侈选项,而是驱动成功的关键要素。运用人工智能驱动分析、数据科学与机器学习的企业正日益超越竞争对手。消费者越来越期待定制化推荐与动态购物体验——这正是 Snowflake ML 的用武之地。

 

通过 Snowflake ML,开发者和分析师可直接在 Snowflake 平台中使用标准 SQL 实现以下功能:

  • 加载与整合数据

  • 构建客户细分画像

  • 训练并部署机器学习模型

  • 生成个性化评分

  • 将结果输送到应用与实时工作流中

 

本文将深入探讨 Snowflake ML 如何为现代电商体验提供简洁、基于 SQL 的个性化解决方案。您将了解如何将客户数据接入 Snowflake,根据行为模式划分客群,并利用 Snowflake ML 构建预测高价值客户的智能模型。无论您是构建个性化工作流的开发者,还是提升营销效果的分析师,这些实践步骤都将助您快速入门。

 

请首先登录您的 Snowflake 账户(访问 Snowflake 网页控制台)。若尚未拥有账户或需测试环境进行学习,可在此免费注册体验。

步骤 1:加载并准备数据

我们将首先创建一个客户订单的小型模拟数据集。

请在 Snowflake SQL 工作表中完整运行以下代码块: 

-- Step 1.0: Create a database and schemaCREATE OR REPLACE DATABASE DATACLOUDDISPATCHSI;USE DATABASE DATACLOUDDISPATCHSI;CREATE OR REPLACE SCHEMA ECOMMERCE;USE SCHEMA ECOMMERCE;-- Step 1.1: Create a customer orders tableCREATE OR REPLACE TABLE CUSTOMER_ORDERS (  CUSTOMER_ID  NUMBER,  ORDER_ID     NUMBER,  ORDER_DATE   DATE,  ORDER_VALUE  NUMBER(10,2),  PRODUCT_ID   NUMBER);-- Step 1.2: Insert sample order dataINSERT INTO CUSTOMER_ORDERS (CUSTOMER_ID, ORDER_ID, ORDER_DATE, ORDER_VALUE, PRODUCT_ID) VALUES(1001,50001,'2023-01-15', 89.99,201),(1001,50022,'2023-03-02',120.49,305),(1002,50110,'2023-05-11', 45.00,110),(1003,50155,'2023-02-19',239.00,402),(1003,50190,'2023-05-22',130.00,233),(1003,50201,'2023-06-01', 99.99,110),(1004,50333,'2023-01-05', 19.99,502),(1001,50390,'2023-11-11',301.00,900),(1005,50400,'2023-12-12', 67.50,702);-- Step 1.3: Verify dataSELECT * FROM CUSTOMER_ORDERS ORDER BY ORDER_DATE;
复制代码

 

该数据集包含重复的客户购买记录、多样化的订单金额以及用于后续客户分群和机器学习建模的实用字段,足以支持基础建模需求。

使用 Snowflake Workspace

若您倾向于通过可视化界面而非 SQL 加载数据,Snowflake Workspace 支持将文件(包括 Excel 和 CSV 格式)直接拖放至环境中。

 

1. 在 Snowflake 左侧导航栏中进入 Projects。

2. 点击下拉菜单中的 Workspaces(如图所示)。

3. 创建并打开一个新的 Workspace。

4. 在 Workspace 内点击+ Worksheet 以新建 SQL 工作表。

5. 运行 SQL 代码前,请确保工作表已设置正确的角色、仓库、数据库与模式。

 

Article content

本教程步骤 1 至 3 中的所有 SQL 命令均需在此 SQL 工作表中粘贴并执行。Snowflake 虽提供 Workspace、Notebook 等多种项目工具,但本教程全程使用标准 SQL 工作表完成。

步骤二:使用 SQL 构建客户细分模型

Snowflake 支持集成机器学习模型,用于预测客户行为、推荐产品及定制促销策略。开发人员可通过 Python 或 R 语言,结合 Snowflake 的 Data Science Workspace 部署模型,该模型可输入客户数据并输出个性化推荐。

 

一种基础的个性化策略是基于客户历史行为进行识别,我们将计算以下指标:

  • 购买频率

  • 客单价(AOV)

USE DATABASE DATACLOUDDISPATCHSI;USE SCHEMA ECOMMERCE;
复制代码

-- Step 2.1: Create customer segmentsCREATE OR REPLACE TABLE CUSTOMER_SEGMENTS ASSELECT  CUSTOMER_ID,  COUNT(ORDER_ID)  AS PURCHASE_COUNT,  AVG(ORDER_VALUE) AS AVG_ORDER_VALUEFROM CUSTOMER_ORDERSWHERE ORDER_DATE BETWEEN '2023-01-01' AND '2023-12-31'GROUP BY CUSTOMER_ID;-- Step 2.2: Inspect customer segmentsSELECT * FROM CUSTOMER_SEGMENTS ORDER BY PURCHASE_COUNT DESC;
复制代码

 

由此构建的 CUSTOMER_SEGMENTS 表将成为机器学习模型的基础数据层。 

步骤三:训练与部署机器学习模型(基于 Snowflake ML 的纯 SQL 实现)

Snowflake ML 支持直接使用 SQL 训练模型,无需依赖 Python 或外部工具。

我们将完成以下任务:

1. 标记“高价值客户”(购买次数 ≥3 次)

2. 训练分类模型

3. 对全部客户进行评分

步骤 3.1:创建训练表

在 Snowflake 中训练机器学习模型前,需为模型提供学习样本。这意味着需要构建一个包含以下内容的表:

  • 特征(模型学习的输入变量)

  • 目标标签(模型需预测的结果)

 

本例中,我们的目标是识别高价值客户。因此,需要在历史数据中创建一列,明确标注哪些客户属于高价值客户。训练表的作用正在于此——它基于步骤二生成的客户分群,新增目标标签列。随后,Snowflake ML 将利用此标注表学习高价值客户的特征模式。

 

-- Step 3.1: Add a target label for modelingCREATE OR REPLACE TABLE CUSTOMER_SEGMENTS_TRAIN ASSELECT    CUSTOMER_ID,    PURCHASE_COUNT,    AVG_ORDER_VALUE,    IFF(PURCHASE_COUNT >= 3, 1, 0) AS TARGET_HIGH_VALUEFROM CUSTOMER_SEGMENTS;SELECT * FROM CUSTOMER_SEGMENTS_TRAIN ORDER BY PURCHASE_COUNT DESC;
复制代码

步骤 3.2:使用 Snowflake ML 训练分类模型

在获得已标注的训练表后,即可训练 Snowflake ML 识别高价值客户的潜在特征。通过训练分类模型,Snowflake 将学习:

  • 应从哪些输入特征中学习规律(如购买次数与平均订单金额)

  • 需要预测的目标结果(即高价值标签:0 或 1)

 

-- Step 3.2: Train the classification modelCREATE OR REPLACE SNOWFLAKE.ML.CLASSIFICATION HIGH_VALUE_MODEL (    INPUT_DATA     => SYSTEM$REFERENCE('TABLE', 'ECOMMERCE.CUSTOMER_SEGMENTS_TRAIN'),    TARGET_COLNAME => 'TARGET_HIGH_VALUE');Snowflake automatically trains and tunes the model based on your training table.(Optional) View metrics:CALL HIGH_VALUE_MODEL!SHOW_EVALUATION_METRICS();
复制代码

步骤 3.3:使用模型对客户进行评分(SQL)

模型训练完成后,即可用于预测。在此步骤中,模型将根据每位客户的购买行为(购买次数与平均订单金额)判断其是否为潜在高价值客户。

 

以下 SQL 命令将每位客户的特征输入模型,并返回预测结果:

-- Step 3.3: Score customersSELECT    s.CUSTOMER_ID,    s.PURCHASE_COUNT,    s.AVG_ORDER_VALUE,    HIGH_VALUE_MODEL!PREDICT(        INPUT_DATA => OBJECT_CONSTRUCT(            'PURCHASE_COUNT', s.PURCHASE_COUNT,            'AVG_ORDER_VALUE', s.AVG_ORDER_VALUE        )    ) AS MODEL_OUTPUTFROM CUSTOMER_SEGMENTS AS s;
复制代码
MODEL_OUTPUT 是什么?

 

Snowflake 将模型的预测结果以 VARIANT 类型(一种结构化对象)返回。您无需运行或执行它——它仅仅是 Snowflake 所展示的结果!

 

为了使预测结果更易于使用,您可以只提取预测类别(0 或 1)。

 

  • 1 表示模型将客户识别为高价值客户

  • 0 表示非高价值客户

 

提取预测类别的语句为:

SELECT    CUSTOMER_ID,    PURCHASE_COUNT,    AVG_ORDER_VALUE,    HIGH_VALUE_MODEL!PREDICT(        INPUT_DATA => OBJECT_CONSTRUCT(            'PURCHASE_COUNT', PURCHASE_COUNT,            'AVG_ORDER_VALUE', AVG_ORDER_VALUE        )    ):PREDICTION:"class"::NUMBER AS PREDICTED_HIGH_VALUEFROM CUSTOMER_SEGMENTS;
复制代码

 

这将为您提供一个清晰的 0/1 指标,用于判断客户是否被视为“高价值客户”。

 步骤 3.4:持久化个性化评分(可选)

至此,您已通过在查询中直接使用模型生成预测,这非常适合探索性分析——但在实际场景中,您通常需要将这些预测存储到表中,以便供仪表板、应用程序、营销活动等重复使用。

 

以下 SQL 语句创建一个名为 CUSTOMER_VALUE_SCORES 的新表,其中包含每位客户、其购买行为以及模型的预测结果。

CREATE OR REPLACE TABLE CUSTOMER_VALUE_SCORES ASSELECT    CUSTOMER_ID,    PURCHASE_COUNT,    AVG_ORDER_VALUE,    HIGH_VALUE_MODEL!PREDICT(        INPUT_DATA => OBJECT_CONSTRUCT(            'PURCHASE_COUNT', PURCHASE_COUNT,            'AVG_ORDER_VALUE', AVG_ORDER_VALUE        )    ):PREDICTION:"class"::NUMBER AS PREDICTED_HIGH_VALUEFROM CUSTOMER_SEGMENTS;SELECT * FROM CUSTOMER_VALUE_SCORES ORDER BY PREDICTED_HIGH_VALUE DESC;
复制代码

 

现在您已拥有一个可用于下游个性化流程的数据表。您可以持续引用这些评分来定位高价值客户、触发个性化优惠、提供推荐内容等。

步骤四:实时个性化

获得每位客户的预测评分后,即可结合实时行为数据提供更智能的个性化推荐。实时行为数据包括:

  • 最近浏览的商品

  • 购物车中新增或移除的商品

  • 浏览或会话事件

  • 实时库存更新

针对更高级的用例,Snowflake 支持在线特征存储,允许应用程序(如网站或推荐引擎)在毫秒级延迟内获取最新的客户特征——包括近期点击行为、会话历史或模型生成的评分。这对于需要在应用用户体验中实现实时个性化(而非依赖批量调度)的场景尤为理想。

 

Snowflake 可通过 Kafka、Kinesis 或 Event Hubs 等工具接收此类流式数据,从而根据客户行为变化持续更新推荐结果。

 

为保持个性化数据的时效性,您还可以通过 Snowflake 任务定期更新推荐表。以下示例展示了一个每小时运行并刷新热门商品推荐的简化任务:

 

--示例:定期更新推荐数据

 

CREATE OR REPLACE TASK PERSONALIZE_RECOMMENDATIONSWAREHOUSE = COMPUTE_WHSCHEDULE = 'USING CRON 0   UTC'ASMERGE INTO LATEST_RECOMMENDATIONS tgtUSING (    SELECT CUSTOMER_ID, PRODUCT_ID, SCORE    FROM ECOMMERCE.RECOMMENDATIONS_STREAM    WHERE SCORE > 0.8) srcON tgt.CUSTOMER_ID = src.CUSTOMER_ID AND tgt.PRODUCT_ID = src.PRODUCT_IDWHEN MATCHED THEN UPDATE SET SCORE = src.SCOREWHEN NOT MATCHED THEN INSERT VALUES (src.CUSTOMER_ID, src.PRODUCT_ID, src.SCORE);
复制代码

此方案使您的应用程序能够始终查询最新、最相关的推荐结果,从而实现完全动态的个性化购物体验。

总结

个性化推荐现已不再局限于手动规则或外部机器学习流水线。借助 Snowflake ML,您可以在 Snowflake 平台内直接驱动端到端的电商个性化推荐。本教程展示了如何:

  • 将全部电商数据整合至统一的单一平台

  • 完全使用 SQL 构建客户细分模型

  • 通过 Snowflake ML 训练机器学习模型——无需 Python 环境

  • 完成客户评分并生成个性化洞察

  • 利用实时数据流和任务机制保持推荐结果动态更新

最关键的是,所有操作均在 Snowflake 内完成——无需数据迁移、无需配置 Python 环境、无需依赖外部服务。这使得开发者、分析师和数据团队能够以前所未有的便捷度,提供高度个性化的购物体验。

 

注:本教程使用 SQL 和 Snowflake ML 进行演示,但 Snowflake 还提供更多人工智能与智能增强功能,可助力规模化扩展个性化应用场景。

想要一键复制代码以便跟随操作吗?

以下是您可以粘贴到 SQL workspace 中的分步最小可复现工作流程:

-- ============================================================-- E-COMMERCE PERSONALIZATION QUICKSTART (SQL-ONLY)-- End-to-end example:--  1. Create database & schema--  2. Load sample orders data--  3. Build customer segments--  4. Prepare training data for ML--  5. Train Snowflake ML classification model--  6. Score customers & optionally persist scores-- ============================================================------------------------------------------------------------------ (Optional) Step 0: Choose a warehouse------------------------------------------------------------------ Uncomment and replace <YOUR_WAREHOUSE> if needed:-- USE WAREHOUSE <YOUR_WAREHOUSE>;------------------------------------------------------------------ Step 1: Create database, schema, and sample CUSTOMER_ORDERS----------------------------------------------------------------CREATE OR REPLACE DATABASE DATACLOUDDISPATCHSI;USE DATABASE DATACLOUDDISPATCHSI;CREATE OR REPLACE SCHEMA ECOMMERCE;USE SCHEMA ECOMMERCE;-- Create the orders tableCREATE OR REPLACE TABLE CUSTOMER_ORDERS (  CUSTOMER_ID  NUMBER,  ORDER_ID     NUMBER,  ORDER_DATE   DATE,  ORDER_VALUE  NUMBER(10,2),  PRODUCT_ID   NUMBER);-- Insert sample e-commerce dataINSERT INTO CUSTOMER_ORDERS (CUSTOMER_ID, ORDER_ID, ORDER_DATE, ORDER_VALUE, PRODUCT_ID) VALUES(1001,50001,'2023-01-15', 89.99,201),(1001,50022,'2023-03-02',120.49,305),(1002,50110,'2023-05-11', 45.00,110),(1003,50155,'2023-02-19',239.00,402),(1003,50190,'2023-05-22',130.00,233),(1003,50201,'2023-06-01', 99.99,110),(1004,50333,'2023-01-05', 19.99,502),(1001,50390,'2023-11-11',301.00,900),(1005,50400,'2023-12-12', 67.50,702);-- Quick preview of raw ordersSELECT * FROM CUSTOMER_ORDERS ORDER BY ORDER_DATE;------------------------------------------------------------------ Step 2: Build customer segments (frequency & average order value)------------------------------------------------------------------ Aggregate behavior to create one row per customerCREATE OR REPLACE TABLE CUSTOMER_SEGMENTS ASSELECT    CUSTOMER_ID,    COUNT(ORDER_ID)  AS PURCHASE_COUNT,    AVG(ORDER_VALUE) AS AVG_ORDER_VALUEFROM CUSTOMER_ORDERSWHERE ORDER_DATE BETWEEN '2023-01-01' AND '2023-12-31'GROUP BY CUSTOMER_ID;-- Inspect segmentsSELECT * FROM CUSTOMER_SEGMENTS ORDER BY PURCHASE_COUNT DESC;------------------------------------------------------------------ Step 3: Prepare training data for Snowflake ML-- Add a label indicating whether a customer is “high-value”-- (in this example: 3 or more purchases)----------------------------------------------------------------CREATE OR REPLACE TABLE CUSTOMER_SEGMENTS_TRAIN ASSELECT    CUSTOMER_ID,    PURCHASE_COUNT,    AVG_ORDER_VALUE,    IFF(PURCHASE_COUNT >= 3, 1, 0) AS TARGET_HIGH_VALUEFROM CUSTOMER_SEGMENTS;-- View training data with targetSELECT * FROM CUSTOMER_SEGMENTS_TRAIN ORDER BY PURCHASE_COUNT DESC;------------------------------------------------------------------ Step 4: Train a classification model with Snowflake ML-- This learns to predict TARGET_HIGH_VALUE from the features-- PURCHASE_COUNT and AVG_ORDER_VALUE.----------------------------------------------------------------CREATE OR REPLACE SNOWFLAKE.ML.CLASSIFICATION HIGH_VALUE_MODEL (    INPUT_DATA     => SYSTEM$REFERENCE('TABLE','ECOMMERCE.CUSTOMER_SEGMENTS_TRAIN'),    TARGET_COLNAME => 'TARGET_HIGH_VALUE');-- (Optional) Inspect training metricsCALL HIGH_VALUE_MODEL!SHOW_EVALUATION_METRICS();------------------------------------------------------------------ Step 5: Score customers with the trained model-- This returns the predicted class (0 = not high-value, 1 = high-value).----------------------------------------------------------------SELECT    CUSTOMER_ID,    PURCHASE_COUNT,    AVG_ORDER_VALUE,    HIGH_VALUE_MODEL!PREDICT(        INPUT_DATA => OBJECT_CONSTRUCT(            'PURCHASE_COUNT', PURCHASE_COUNT,            'AVG_ORDER_VALUE', AVG_ORDER_VALUE        )    ):PREDICTION:"class"::NUMBER AS PREDICTED_HIGH_VALUEFROM CUSTOMER_SEGMENTSORDER BY PREDICTED_HIGH_VALUE DESC, PURCHASE_COUNT DESC;------------------------------------------------------------------ Step 6 (Optional): Persist personalized scores for downstream use-- This creates a reusable table that other teams, dashboards,-- and applications can query.----------------------------------------------------------------CREATE OR REPLACE TABLE CUSTOMER_VALUE_SCORES ASSELECT    CUSTOMER_ID,    PURCHASE_COUNT,    AVG_ORDER_VALUE,    HIGH_VALUE_MODEL!PREDICT(        INPUT_DATA => OBJECT_CONSTRUCT(            'PURCHASE_COUNT', PURCHASE_COUNT,            'AVG_ORDER_VALUE', AVG_ORDER_VALUE        )    ):PREDICTION:"class"::NUMBER AS PREDICTED_HIGH_VALUEFROM CUSTOMER_SEGMENTS;-- Final scored outputSELECT * FROM CUSTOMER_VALUE_SCORESORDER BY PREDICTED_HIGH_VALUE DESC, PURCHASE_COUNT DESC;
复制代码

原文地址:https://www.linkedin.com/pulse/how-leverage-snowflake-intelligence-e-commerce-personalization-60fhc/?trackingId=SamHZTb8T76gKESH2PP2SA%3D%3D

实用工具分享:MCP Toolbox 轻松实现查库、执行 SQL、造数据

Toolbox 一款便捷实用的工具,核心支持数据库查询、SQL 直接执行、快速造测试数据三大核心场景,能大幅提升数据相关工作与 AI 联动的效率~

一、下载与安装 MCP Toolbox

  1. 官方下载地址(请选择对应自身操作系统的版本):
    https://github.com/googleapis/genai-toolbox/releases
  2. 安装后赋予执行权限并验证版本(适用于 Mac/Linux 等类 Unix 系统):
# 赋予 toolbox 可执行权限 chmod +x toolbox

# 验证工具是否安装成功,输出版本号即代表可用
./toolbox --version

补充提示:Windows 系统无需执行 chmod 赋予权限操作,直接在命令行中运行 toolbox.exe --version 即可完成版本验证。

二、配置对接 AI 工具(以 Claude 为例)

通过以下 JSON 配置文件,实现 Claude 与 MCP Toolbox 的联动,核心配置 MySQL 数据库连接信息(其他数据库可参考官方文档进行扩展配置):

{ "mcpServers": { "mysql": { "command": "./PATH/TO/toolbox", // 替换为你的 toolbox 实际文件存放路径 "args": ["--prebuilt", "mysql", "--stdio"], "env": { "MYSQL_HOST": "", // 数据库主机地址,本地环境通常填写 127.0.0.1 "MYSQL_PORT": "", // 数据库端口,MySQL 默认端口为 3306 "MYSQL_DATABASE": "", // 要连接的目标数据库名称 "MYSQL_USER": "", // 数据库登录用户名 "MYSQL_PASSWORD": "" // 数据库登录密码 } } } } 

三、配置生效与使用

  1. 完整填写上述配置文件中的各项空缺(重点替换工具路径与数据库连接信息),填写完成后保存文件;
  2. 重启你的 Claude 工具(或对应的 AI 客户端);
  3. 重启完成后,即可在 Claude 中调用 MCP Toolbox 实现查库、执行 SQL、造测试数据等操作啦~

补充说明

  1. 除 MySQL 外,MCP Toolbox 还支持多种主流数据库,完整预构建工具列表可前往官方仓库查看;
  2. 若配置后无法正常连接数据库,优先排查:数据库服务是否正常启动、连接信息是否填写正确、toolbox 实际路径是否匹配;
  3. 项目官方仓库详情:GitHub - googleapis/genai-toolbox: MCP Toolbox for Databases is an open source MCP server for databases.

📌 转载信息
原作者:
geekjair
转载时间:
2026/1/10 19:00:16

  纯情博客为您提供最新网络安全黑客信息资讯

  去年7月,腾讯安全御见威胁情报中心首次检测到木马,利用的高危漏洞侵入企业服务器进行挖矿;11月黑客纯情,再次看到更新到6.0版本的挖矿木马变种,专门对于企业SQL服务器的1433端口爆破防御进行蠕虫式传播。

  近期,木马的踪迹再次被腾讯安全御见威胁情报中心检测捕捉,此次的样本依然专门对于企业1433端口,控制企业机器后进一步植入挖矿木马进行挖矿获利。目前,腾讯安全团队借助溯源分析已锁定发起该木马攻击活动的被曝团伙和控制者。

  通过与之前的功击活动进行对比评析,腾讯安全学者强调,在这次的挂马攻击中不法黑客使用的爆破工具加密方法与7月末发现的挂马样本保持一致。解密后样本以组件名“koi”加载执行,在云端配置文件的储存方法、加密形式均与7月攻击事故中的相似,都辅以web页面保存黑客博客,并借助改造后的算法进行加密。

  在顺利入侵机器后,攻击者会首先植入远程控制木马。据认识,这是著名远控木马Gh0st的更改版本,安装运行后与控制端搭建联系,导致服务器被不法黑客完全控制,受害者机器的鼠标记录等一系列用途就会被防御者执掌,之后再进一步植入挖矿木马,通过挖取门罗币亏损。

  黑客抓肉鸡

  (图:细菌作者在黑客论坛传播挖矿木马生成器)

  黑客抓肉鸡

  腾讯安全御见威胁情报中心通过追溯此次不法黑客攻击使用的SQL爆破工具的解压路径“1433腾龙3.0”黑客抓肉鸡,发现了一个与防御事件相关联的黑客技术论坛——腾龙技术峰会,并经过信息对比,确认了其中某位活跃组员与C2地址的某个可疑域名登录者为同三人。从现有的线索来看黑客抓肉鸡,该组员在该黑客论坛下载的挖矿木马生成器生成了这次传播的挖矿木马执行文件。由此可以猜测,“”系列防御事件应当是该科技峰会资深组员或队伍所为,不法黑客运用所学到的近程防御科技攻击并控制被害用户机器成为养鸡培训脚本,植入挖矿木马牟利。这种使用违法方式侵入企业网路、并借助别人计算机平台挖矿的行为已违犯国家法律。

  黑客抓肉鸡

  (图:腾讯御点终端安全管控系统顺利拦截该木马病毒)

  对此,腾讯安全学者提醒企业顾客,应提升警觉,应尽早加固SQL服务器,修补服务器安全漏洞;引入安全的密钥策略,避免使用弱口令,特别是sa帐户密码,防止不法黑客暴力破解。针对挖矿木马的特点,企业顾客可在原始配置基础上修改默认1433端口设置,并设定访问规则、拒绝1433端口探测。推荐客户使用腾讯御知网络空间风险雷达进行风险扫描和安全监视,并布署腾讯御点终端安全管控系统应对恶意伤害。企业网站管理员可使用腾讯云网页管家智能防护平台,目前该系统已具有Web入侵防护,0Day漏洞补丁修补等多纬度防御策略,可全面保护网站平台安全。