AI时代的实时分析三大范式:从Apache Doris到SelectDB实践

发布时间:2026/10/8 7:13:30
AI时代的实时分析三大范式:从Apache Doris到SelectDB实践 这几年实时分析圈子的变化真的比我预想中要快。Apache Doris 是开源实时数据仓库里绕不开的项目我和团队在好几套系统里用过它SelectDB 则是 Doris 背后的商业化云服务把同一套引擎搬到云上做成托管产品。真正让我意识到需要重新梳理思路的是 AI 大规模落地之后业务方来找我问的最多的不再是“报表多久能刷新”而是“能不能让 AI 直接用库里的最新数据回答客户、跑分析、辅助决策”。这个转变看起来只是问题形式变了实际上背后是实时分析的整体范式在变。参考我和几个数据团队这两年的实践我把 AI 时代的实时分析拆成三个可以独立落地、又可以叠加使用的范式后面会逐个展开讲原理、给示例、晒实操心得。这篇文章适合谁看一是正在做数据架构选型、被“实时 AI”两个词夹击的工程师二是已经在用 Doris 但只拿它跑报表、想往 AI 场景延伸的团队三是想评估 SelectDB 这类云服务值不值的负责人。先把整个体系在脑子里立起来后面落地时就不容易走偏。1. 为什么 AI 时代要重新定义实时分析1.1 分析需求正在从“给人看”转向“给模型用”过去做实时分析目标用户是人。运营看大屏、管理层看 BI、研发看监控查询结果最终都要落到人的理解和决策上。人的响应速度慢对延迟的容忍度高报表一分钟刷新一次已经很不错。但 AI 时代不一样数据消费方变成了大模型、推荐系统、风控引擎和各类 Agent。模型不会像人一样等报表它需要的是在几百毫秒内拿到最新、最准确的数据作为上下文。典型场景就有几个推荐系统要根据秒级行为更新用户特征客服机器人要用最新订单和工单信息生成回答风控模型要实时校验每一笔交易。这些场景里数据晚一分钟结论就可能完全跑偏。这也是我判断“实时分析三大范式”需要被重新定义的根本原因——消费对象变了技术架构必须跟着变。1.2 旧架构断裂在哪里很多团队现在的实时链路还是老一套业务库发消息到 KafkaFlink 做流式计算结果写入 Redis、MySQL 或者 Elasticsearch再叠加一个 ClickHouse 或者 Doris 给分析师用。链路一旦拉长问题就跟着来。第一是延迟叠加每多一跳就多几十甚至几百毫秒第二是数据一致性同一份数据在 Redis、MySQL、OLAP 里各存一份经常出现对不上的情况第三是运维成本消息、流、库、缓存全要照顾任何一个环节抖动都会影响整体。我见过不少团队最后绕不开一个结论与其维护一条长链路不如把“导入、存储、查询、服务”四件事放在一个引擎里做。这正是 Doris 早期定位里“One Data Architecture”思路的落地。它的列式存储、向量化执行、多表模型让它在做复杂分析的同时也能承接高并发服务化查询天然适合当作 AI 时代的数据底座。1.3 三大范式到底是什么先把后面要展开的框架交代清楚后面好对号入座。我把 AI 时代的实时分析拆成三个相互独立又能叠加的范式。第一个是“实时数仓范式”核心是把数仓从报表工具变成数据服务用高并发点查能力支撑前台业务系统解决从“查得动”到“查得快”的问题。第二个是“湖仓一体范式”核心是把企业数据湖里的海量原始数据通过统一元数据的方式接入实时数仓让同一份数据既能喂给模型做训练又能支撑分析查询解决“数据孤岛”和“一份数据多处存储”的问题。第三个是“AI 融合范式”核心是让数仓直接给大模型和 Agent 提供工具能力包括向量检索、知识库召回和 Text-to-SQL解决“模型拿不到实时数据”的问题。这三者不是互相替代的关系而是层层递进。底下必须先有实时数仓把数据管好再用湖仓一体把数据范围扩大最后 AI 才能在完整、新鲜的数据上做理解与决策。后面每个范式我都会拆解原理、给出实操建表和示例尽量让你看完能直接抄作业。2. 范式一实时数仓——把数据仓库做成数据服务2.1 从“跑批出报表”到“高并发 API 化”第一范式解决的是最朴素的需求数据要快。这里的快不是指一个复杂分析从十秒变一秒而是指业务系统直接调用数仓在毫秒级返回结果。最典型的场景是用户画像。以前做画像常见做法是凌晨批算生成一张大宽表白天用 Redis 缓存提供查询。但一到数据量上来宽表动辄几亿行字段几十上百个Redis 内存根本装不下想支持多维组合过滤比如“最近 30 天活跃且消费金额大于一千元且偏好某类商品”这种条件Redis 的简单的 key-value 结构也很吃力。Apache Doris 在高频服务化查询上有一套比较成熟的打法。核心是 Unique Key 表模型配合前缀索引与分桶裁剪。导入时按主键去重并标记最新版本查询时通过前缀索引快速定位到少量分桶再在桶内做稠密索引扫描。这套机制让 Doris 可以在单集群承担每秒上千甚至更高 QPS 的点查且延迟 p99 稳定在百毫秒以内。相比 Redis它赢在三点一是 SQL 表达能力完整各种条件组合、聚合、Join 都能写二是数据天然有历史版本不会因为覆盖而丢失三是容量大得多几十 TB 都在设计范围之内。这也是我认为“实时数仓范式”的第一层把数据仓库从给人看的系统变成给系统用的服务。2.2 关键机制拆解为什么它能点得快理解 Doris 的高并发能力得先看三层设计。第一层是存储模型。Doris 的三种表模型里Duplicate Key 适合明细追加Aggregate Key 适合预聚合Unique Key 适合主键更新。高并发点查场景几乎全部落在 Unique Key 上。早期 Unique Key 走 Merge-On-Read查询时要合并多个版本的数据导致点查和聚合都会有额外开销。从 2.0 版本开始官方主推 Merge-On-Write数据导入时就把同主键的历史行标记删除、新行直接可见。这样查询时不再需要临时合并代价是写路径稍重但对查询性能的提升非常明显。现在的新版本里MOW 已经是高并发场景的默认选择。第二层是索引结构。Doris 每一列都有对应的索引信息表构建时会在前缀列上建立稀疏排序索引再配合分桶的哈希裁剪让查询在绝大多数情况下只需要扫描非常小的数据范围。前缀索引最长 36 字节所以在设计上有讲究前缀列尽量选区分度高的整数或短字符串像是 user_id、order_id 这种而不是长字符串否则截断会导致索引价值打折。第三层是 Compaction 机制。实时导入会产生很多小版本如果不处理查询会退化。Doris 的 Compaction 在后台持续把小版本合并成大版本有 Base Compaction 和 Cumulative Compaction 两层配合。它的设计目标是让 Compaction 对查询造成的影响尽量小这一点我在实际压测中确认过持续导入的场景下点查延迟依然能保持稳定。2.3 实操一张能支撑高并发服务的画像表怎么建直接给一份能抄的例子。假设我们要建用户画像宽表主键是 user_id指标字段若干需要按最近消费时间和城市过滤同时高频读取用户状态。CREATE TABLE user_profile ( user_id BIGINT NOT NULL, city_id INT NOT NULL, last_pay_time DATETIME NOT NULL, gender TINYINT, level INT, total_amount DECIMAL(12,2), recent_views INT, attribute MAPSTRING, STRING ) UNIQUE KEY(user_id) DISTRIBUTED BY HASH(user_id) BUCKETS 64 PROPERTIES ( unique_key_merge_on_write true, replication_num 1 );几个实操要点。第一分桶数不要拍脑袋。官方建议单个分桶的数据量控制在 10GB 到 20GB 之间可以先预估数据总量再倒推桶数。比如总数据量约 50GB分 4 到 8 个桶比较合适桶太多会放大元数据和 Compaction 压力。第二查询条件要尽量落到前缀列上。表的主键是 user_id点查指定 user_id 可以精确裁剪如果业务经常按 city_id 过滤就把 city_id 放到前缀列组合里但注意前缀列顺序不能随意调。第三不要在每列上都加索引尤其不要对低区分度的列强行建索引。Doris 的倒排索引INVERTED适合全文和子字符串匹配但用多了会增加写放大。另外一个建议是给高频过滤条件建物化视图。比如系统经常按 city_id 聚合统计可以针对这个维度单独建一个 Rollup 或异步物化视图查询走视图而不是全表扫描。物化视图的选择要克制只覆盖真正高频的查询模式否则会变成存储和写入的负担。最后说下实测体感。我们之前压测过一个 10 亿行量级的 Unique 表纯点查 QPS 到 1500 左右p99 延迟在 80ms 上下加上 city_id 等 2 到 3 个过滤条件的复合查询QPS 会掉到 600 到 800但延迟依然在百毫秒量级。这个表现足够支撑绝大多数业务 API 的实时数据需求。提示如果并发请求来自同一个应用建议走 JDBC 或 HTTP 的预编译语句PreparedStatement并且开启 Doris 的 Query Cache能显著降低重复 SQL 的解析开销。踩过坑的都知道瓶颈常常不在数据扫描而在重复解析和网络往返。3. 范式二湖仓一体——用 Doris 统一湖与仓3.1 湖与仓的矛盾最后都变成“数据要两份”数据湖这几年在企业里铺得很开典型组合是 Hive 存原始明细Iceberg/Hudi/Paimon 做增删改和快照。好处是开放、便宜、能存大规模原始数据。坏处也明显尤其是查询性能Iceberg 和 Hudi 的查询通常要起 Spark 或 Flink 作业一次全量扫描经常等几分钟这对分析师和 AI 应用来说都不友好。数据仓库这边相反列存、索引、向量化执行都在为性能服务但想吃到湖里的数据就得先做一轮又一轮的同步把数据从湖搬到仓。结果就是同一份数据在湖里一份、在仓里一份两份还要定版本对齐。我们团队早期也是这么干的半夜用调度任务导数据第二天白天才发现数据口径对不上非常痛苦。后来切到 Doris 的 Multi-Catalog 方式把 Hive/Iceberg/Hudi/Paimon 都注册成外部 CatalogDoris 作为一个入口统一查询湖内数据需要加速的表再用物化视图落到内部存储。这样既不用把数据全搬走又能让高频查询获得数仓级性能。3.2 用 Multi-Catalog 查湖用物化视图加速建外部 Catalog 很简单以 Hive 为例CREATE CATALOG hive_catalog PROPERTIES ( type hms, hive.metastore.uris thrift://172.16.10.10:9083 );注册之后就能直接查表了。Doris 和外部表的交互不是简单的“拷一份”而是尽量做下推分区裁剪会传到 MetaStore谓词条件会传到文件扫描层列裁剪只读需要的列。这些看起来是基本能力但在实际性能上差别很大尤其是查 Iceberg 时能否把 condition 下推到 manifest 层直接决定了扫描量。我用同一张 Iceberg 表做过对比支持下推的查询扫描行数能少一个数量级。对于频繁访问的湖表我建议在 Doris 里建异步物化视图而不是长期依赖外表直查CREATE MATERIALIZED VIEW mv_user_daily BUILD DEFERRED REFRESH AUTO ON MANUAL AS SELECT user_id, city_id, DATE(last_pay_time) AS pay_date, SUM(total_amount) AS amount, COUNT(*) AS cnt FROM hive_catalog.db1.orders GROUP BY user_id, city_id, DATE(last_pay_time);物化视图相当于把外部查询结果固化到 Doris 的内部列存里后续的报表、特征查询直接走内表性能和稳定性都有保证。刷新策略我一般用 ON MANUAL 定时任务凌晨刷新昨天分区白天只查不改。自动 refresh 在数据湖场景里容易触发大量扫描需要谨慎配置。这里有一个常见争论湖里的数据要不要回填到仓里。我的观点是不必全量回填只物化真正被高频查询的核心表。原始明细、日志、未清洗的数据继续留在湖里由统一元数据管理。Doris 的 Catalog 能让你在同一个会话里 Join 内表和外表这在免去数据搬迁的同时保持分析能力这是湖仓一体比传统“搬迁式”架构舒服很多的地方。3.3 AI 训练与特征场景怎么用上湖仓一体湖仓一体对齐到 AI 场景核心价值是解决训练数据和特征数据的分裂问题。AI 团队通常需要三类数据全量原始数据做训练、实时特征做推理、标签数据做评估。如果没有统一入口这三类数据会散落在数据湖、Redis、OLAP 三处AI 工程师光是找数据就要花很多时间。用 Doris 湖仓一体可以这样组织原始数据继续存在湖上 Iceberg/Hudi 表Doris 通过 Catalog 读取湖表用 SQL 算出特征宽表特征宽表物化成内部表供在线推理读取同时训练集可以直接从 Doris 导出到对象存储交给训练平台。批与流在这里可以共用一套数据模型Spark 或 Flink 写湖Routine Load 或 Flink CDC 写仓两边用同一个 Catalog 元数据管理最后 AI 团队只用面对 Doris 一个查询入口。我自己的经验是这个范式落地时要特别注意两点。第一Catalog 命名规范要提前定好比如生产环境只允许通过统一 Catalog 访问禁止直接连底层文件否则权限会失控。第二千万要对齐时间语义。湖上的 Iceberg 表快照和 Doris 内表的实时数据天然有时间差做训练集时要在 SQL 里显式指定时间范围否则容易把“不同时间口径”的数据混在一起模型效果很难复现。这个问题我们吃过亏后来所有训练集导出任务都固定使用统一的时间分区条件。4. 范式三AI 融合——实时分析变成 AI 的工具箱4.1 为什么实时数仓要做向量检索AI 应用落地最常见的需求是语义检索和知识召回。比如客服机器人要先从知识库或历史工单里找出“语义相似”的记录再结合这些记录生成回答。传统实现是单独部署一个向量数据库把文档或记录切块、生成 embedding、写入向量库。而业务数据仍在 Doris 里变成两套系统数据双写、口径分裂、联合过滤困难。Doris 从 2.1 开始内置了向量能力把向量字段和普通字段放在同一张表里。你可以建一个带 Array 类型的表对向量列建 HNSW 或 IVF 索引然后在一条 SQL 里同时完成业务条件过滤和向量相似度排序。这是向量数据库很难做到的事情向量库通常很难高效表达“状态为已支付、城市在北京、时间在最近 7 天”这种结构化条件Doris 可以把结构化条件压到最小范围再去做向量计算。举例SELECT id, title, content, distance(embedding, [0.12, 0.34, ...]) AS score FROM doc_knowledge WHERE status active ORDER BY score ASC LIMIT 5;这里distance()函数按向量距离返回最相似的记录。从工程角度看Doris 的向量索引演进还在持续优化中单就大规模向量 高并发检索这个组合来说它比“向量库 关系库”拼装出来的方案简单不少。选型时要留意向量维度、距离函数是否和索引类型匹配后面我会在问题章节单独讲。4.2 RAG 与知识库从文档知识到实时数据传统 RAG 的流程是文档切块 → 向量化 → 存向量库 → 检索 → 喂给大模型。这套流程在数据不常变化的场景下没问题但企业内部的客服、销售、运维场景数据是实时变化的。文档库里不会更新“这个客户今天刚下单”“这台设备刚刚报警”而这些问题恰恰需要实时数据回答。更务实的做法是把 RAG 的“知识库”升级为“数据库”让大模型需要时直接从 Doris 拿实时明细。比如智能客服场景用户的提问先做 embedding然后在 Doris 一张工单表里做向量召回同时用 user_id、时间、订单状态等结构化条件做过滤。回答的上下文就不再是几段过期的静态文档而是“该用户最近遇到的实际问题”。这种做法把 RAG 的元数据过滤从“简单标签”升级成了完整的 SQL 能力可控性和准确率都会好很多。实操上我会这么做在 Doris 建一张知识混合表既存文本切片和 embedding也存业务标签列建一个 API 服务封装检索逻辑应用侧只传参数。这样模型不会直接看到数据库结构权限和 SQL 风险都被挡在 API 层。另外建议每次批量刷新 embedding 时记录版本号检索时按版本过滤避免新旧向量混用导致的召回混乱。4.3 Text-to-SQL 与 Agent让模型学会调用实时数据接下来是 AI 融合范式里最热的方向让大模型直接通过自然语言查数。很多团队光速把大模型接上数据库连接串很快发现三个问题模型生成的 SQL 经常有语法或语义错误没有权限控制模型可能查任意表任意字段一次生成的全表扫描直接拖垮线上集群。我建议的正确姿势是两层隔离。外层是 Agent负责理解自然语言、规划动作、调用工具内层是受控的数据服务只暴露预先定义好的 SQL 模板或受限查询接口Agent 在模板里填参数。Doris 扮演的就是内层数据服务的角色通过 HTTP API 或精心封装的 JDBC 接口接收参数化查询。如果需要让模型生成较自由的 SQL至少要做三件事只授予只读账号限制查询超时和返回行数SQL 生成后用 EXPLAIN 做一轮前置校验发现扫描行数过大就拒绝执行。Doris 的资源组Workload Group可以按账号或查询特征限流这在大模型接入场景里几乎是必须配置的。我在项目里踩过一个典型的坑一开始给 Agent 用的账号是全库权限结果测试阶段模型的随机探索把一个几百亿行的明细表全扫了一遍集群 CPU 直接拉满。后来收紧账号权限、只开放聚合视图并且把所有 Agent 查询都路由到独立 Workload Group设置 30 秒超时和内存上限之后再没出过事故。这是 AI 融合范式落地时最容易被忽略但又最重要的一课。5. SelectDB把三大范式变成开箱即用的云服务5.1 为什么需要 SelectDB开源很强大但运维很现实Apache Doris 功能很全但生产环境要搞好需要有人管部署、配置、监控、升级、容量规划。很多中小团队没有专职数仓运维或者项目周期短没有时间从零搭集群。SelectDB Cloud 做的事情就是把 Doris 变成全托管服务底层存储与计算分离计算组Warehouse可以独立扩缩容存储用对象存储持久化数据不随计算节点变化而丢失。对 AI 团队来说计算隔离是很实用的功能。可以把报表查询放在一个 WarehouseAI 应用的高频查询放在另一个 Warehouse两边互不干扰。流量高峰时让 AI 的 Warehouse 自动扩容低峰自动缩容成本跟随实际用量走。这套模型跟以往“买一台大机器”的思路完全不同特别适合多团队共用一个集群的场景。5.2 开源 Doris 与 SelectDB 选型对照直接给对照表方便决策。对比维度开源 Apache DorisSelectDB Cloud部署运维自建集群需投入运维人力云上托管开箱即用扩缩容手工评估、扩容节点计算组弹性伸缩按需配置存储模式本地存储为主可用对象存储存算分离存储随用随付成本结构固定机器成本计算 存储按用量需关注 CU 消耗功能版本跟随社区版本商业版本含企业级管理、技术支持适用团队有数仓/运维团队数据不出域要求严格团队小、周期紧、希望快速落地5.3 低成本玩转 SelectDB 的几个建议先说成本。SelectDB 按计算资源CU/时长和存储计费最容易烧钱的做法是没限制地跑大查询。建议从一开始就设置查询超时、内存限制把数仓账号按部门拆开每个账号绑定额度。第二AI 场景的并发查询模式和其他分析不一样通常单条 SQL 很小、次数非常多要按 QPS 估算计算组规格而不是按数据量估算。第三能用物化视图榨干重复计算就别让每一条查询都重新扫表。最后如果只是验证想法先用免费试用或小额配额把原型跑起来确实稳定了再决定要不要整体搬迁。6. 常见问题与排查技巧实录6.1 实时导入的乱序与重复最常被问的是 Unique Key 表导入重复数据怎么保证最终一致。Doris 提供了 Sequence Column 机制可以在写入时指定某个字段作为版本号比如业务系统自带的 event_time 或 update_time。同主键多条数据到达时Doris 比较 Sequence Column 的大小保留更大的一条。如果不用它那么数据到达顺序就决定了最终结果上游乱序时会出现旧数据覆盖新数据的问题。我强烈建议所有 Unique Key 表都配 Sequence Column尤其是有 CDC 同步场景的。ALTER TABLE user_profile ADD COLUMN version BIGINT KEY DEFAULT 0;然后导入时通过列映射指定 version 为数据里的事件时间戳。另外实时导入最好用幂等的 Stream Load 或 Routine Load配合导入标签label做去重避免同一批数据因为网络重试被写入两次。6.2 查询性能问题怎么定位慢查询排查我一般按三步走。第一步看 Explain确认扫描行数和 Join 顺序最常见的问题是过滤条件没有下推到存储层比如在 WHERE 里对列使用函数WHERE DATE(ts) 2024-01-01索引就失效了改成ts ... AND ts ...通常扫描量差一个数量级。第二步看 ProfileDoris 的 Profile 能展示每个算子耗时可以快速定位是扫描慢、Join 慢还是网络传输慢。打开 Profile 的方式因版本而不同一般是在 Session 里开启后执行查询再到相关页面拉结果。第三步看 FE/BE 日志确认是否有 Compaction 滞后或 Broker 负载异常。深翻页问题也要提醒LIMIT 10000, 20这种写法会把前面一万行都扫描掉建议用游标、分页键或者把翻页条件改成范围查询。6.3 AI 场景里的几个专属坑AI 集成的坑比传统分析更隐蔽。先说向量检索没生效。如果建了索引但查询计划里没走索引多半是距离函数或向量维度跟索引定义不一致或者是过滤条件太宽导致优化器认为全扫更快。其次做余弦相似度前一定要保证 embedding 已经归一化否则结果排序会失真。第三RAG 检索时如果没有把业务过滤条件作为索引列而只是在向量召回之后做内存过滤数据量大了响应会劣化正确做法是让结构化列出现在过滤条件下推里。第四Text-to-SQL 的权限控制必须单独设负责生成 SQL 的服务账号绝不能有 DDL 权限也不要有访问元数据库的权限。最后大模型连接数不大但每次都可能触发全表扫描所以务必让模型服务走独立 Workload Group。写到这里我自己也在心里把这三大范式过了一遍。说实话最早接触 Apache Doris 时我只当它是一个快一点的 OLAP 引擎后来在数据湖接入和向量检索的实践里逐渐意识到它在 AI 时代的角色已经变了不再只是“给人看报表”的工具而是整个数据体系的出口和底座。SelectDB 的价值则在于把这件事的门槛降下来让没有专职数仓工程师的团队也能快速跑起来。这几次经验让我最深的体会是技术选型时可以追求新但落地时一定要克制。凡是接入 AI 的查询都必须可控、有权限、有限流宁可让模型多问一次也不能让它把整个集群拖垮。AI 时代的数据分析拼的往往不是某个单点功能有多炫而是数据链路是否完整、口径是否统一、权限是否清晰。希望这篇整理能帮你少走一点弯路。