RisingWave 中的 Keys 体系:Stream Key 与存储主键(Storage Primary Key)深度解析
数据库流处理后端数据工程【免费下载链接】risingwaveEvent streaming platform for agentic AI. Continuously ingest, transform, and serve event streams in real time, at scale.项目地址https://gitcode.com/gh_mirrors/ri/risingwave点击查看免费下载RisingWave 的流式计算与存储层围绕两类 Key 展开设计用于在流中唯一标识记录、驱动下游状态维护的Stream Key以及用于决定存储层数据排序与检索效率的存储主键Storage Primary Key。本文以仓库设计文档 docs/dev/src/design/keys.md 为骨架结合前端优化器与编目层源码系统讲解两类 Key 的定义、约束、推导逻辑与协同关系帮助读者理解EXPLAIN计划中stream_key、pk_columns、pk_conflict等字段的真实含义并掌握如何在物化视图、表与 Sink 的建表建视图实践中正确使用 ORDER BY、DISTRIBUTE BY 等语法来影响 Key 的构成。一、两类 Key 的总体定位在 RisingWave 中Key 并不只有 SQL 语义下的主键PRIMARY KEY一种。流式执行与存储分别对记录标识提出了不同的要求最终演化出两类职责互补的 KeyKey 名称作用域核心职责Stream Key流Stream在流中唯一标识一条记录供下游算子维护 per-record 状态、实现更新Update/删除Delete对齐存储主键Storage Primary Key内部又称 pk存储层唯一标识存储中的记录并决定 Key-Value 在存储中的排序从而支持有序扫描两者的关系可以概括为Stream Key 负责流上如何定位记录存储主键负责存储中如何组织记录而更新流恰好通过 Stream Key 找到存储主键对应的整条记录再完成状态的定点更新。二、Stream Key流内记录的身份标识2.1 定义与直观示例Stream Key 是能在 RisingWave 流中唯一标识一条记录的列组合。设计文档给出了一个非常直观的示例假设某个流分块Stream Chunk的 Stream Key 为k1, k2| op | k1 | k2 | v1 | v2 | |----|----|----|----|----| | - | 1 | 2 | 1 | 1 | | | 1 | 2 | 3 | 4 | | | 0 | 1 | 2 | 3 |其中op列表示操作类型-表示删除Delete表示插入Insert。对照 Stream Key(k1, k2)可以读出对于键(1, 2)记录从(1, 2, 1, 1)更新为(1, 2, 3, 4)即先删除旧值、再插入新值对于键(0, 1)记录(0, 1, 2, 3)是新增插入。2.2 Stream Key 不要求是最小标识集合文档特别强调Stream Key不一定是能够标识记录的最小列集合。最典型的情况是分组键group key即分布键/distribution key也会被并入 Stream Key用于规定记录的分布方式。这在源码中得到印证前端优化器的 derive.rs 中的 derive_pk 函数 在推导 Stream Key 时首先将用户要求的分布方式user_distributed_by中的分布列dist_column_indices加入 Stream Key然后再追加输入计划的expect_stream_key()并做去重。也就是说只要一条 SQL 指定了DISTRIBUTE BY之类影响分布的要求对应的列就会成为 Stream Key 的一部分——即便仅凭这些列并不能唯一标识记录但它们保证了相同键的记录一定落在同一个计算节点/分区上这是流式 join、聚合等算子本地维护状态的前提。2.3 流上的一致性约束Insert 与 Delete 必须交替既然下游算子依赖 Stream Key 来维护每个键的独立状态流本身就必须满足以下约束文档原文语义同一个 Stream Key不允许连续出现两次 Insert中间必须夹着一次 Delete同一个 Stream Key不允许连续出现两次 Delete中间必须夹着一次 Insert对于更新UpdateDelete 侧的值必须匹配该 Stream Key 上一次产出的旧值。举例若 Stream Key(1, 2)的上一次值是(1, 2, 1, 1)那么更新到(1, 2, 3, 4)必须表示为| op | k1 | k2 | v1 | v2 | |----|----|----|----|----| | - | 1 | 2 | 1 | 1 | | | 1 | 2 | 3 | 4 |删除一个与旧值不同的记录是非法操作。原因正如文档所述下游算子正是以 Stream Key 为索引来维护各自的 per-record 状态聚合中间值、Join 缓存、Top-N 堆等如果 Delete 的旧值与算子状态中的记录不一致状态将无法正确回退最终导致结果错误或状态泄漏。2.4 源码中的体现Stream Key 在代码中直接落为计划节点的属性。例如physical_table.rs 中TableFragments相关的表目录以stream_key: Vecusize记录 Stream Key 对应的列索引usize指向输出列的序号external_table.rs 中外部表同样维护stream_key: Vecusize并通过 protobuf 序列化传递StreamMaterialize节点在 stream_materialize.rs 构造时以Some(table.stream_key())写入自身的 PlanBase使下游能直接读取本节点产出的 Stream Key。此外TTL数据过期场景下系统会把 TTL watermark 列追加到 Stream Key 中。相关逻辑位于 stream_materialize.rs 的 derive_table_catalog当一行数据进入带 TTL 的表却查不到时无法判断它是新行还是对已过期行的更新把 TTL watermark 列加入 Stream Key 可以确保下游作业视角下不会出现双重插入。三、存储主键Storage Primary Key存储层的有序骨架3.1 与 SQL 主键的本质区别文档明确指出这里讨论的Primary Key是流式算子中常见的内部主键pk它不同于 SQL 里的 PRIMARY KEY更恰当的名字是Storage Primary Key存储主键。它的职责有两层唯一标识存储中的一条记录——类似传统数据库主键提供排序属性ordering property——这是它在 RisingWave 存储模型中更关键的作用。RisingWave 的存储层Hummock本质是一个按 Key 排序的 Key-Value 存储扫描结果天然按 Key 有序。因此物化视图的状态表如何排序完全由存储主键决定。3.2 一个完整的例子ORDER BY 如何改写存储主键文档给出了经典示例create table t1(id bigint primary key, i bigint); create materialized view mv1 as select id, i from t1 order by i, id;mv1的执行计划EXPLAIN输出如下StreamMaterialize { columns: [id, i], stream_key: [id], pk_columns: [i, id], -- notice the pk_columns pk_conflict: NoCheck } └─StreamTableScan { table: t1, columns: [id, i] }注意虽然上游表的 SQL 主键只是id但pk_columns却是[i, id]。原因正是存储层 Key-Value按键排序的性质物化视图声明了order by i, id为了在遍历存储时能按正确的顺序逐条产出记录存储主键必须为[i, id]其中i位于键的前缀位置。这样按分区per partition顺序迭代 Key 时返回的记录天然满足i, id的排序无需额外排序开销。3.3 更新流如何与存储主键协作存储主键除了排序还承担定位功能。当更新流到达时系统先利用Stream Key即id定位需要更新的记录通过该id取出存储中的整条旧记录从旧记录中读出i的旧值用(i, id)组成存储主键对物化状态进行定点更新。这正是两类 Key 协同的典型链路Stream Key 负责流上的身份存储主键负责存储中的地址二者通过取整条记录、再读前缀列的方式完成桥接。文档强调不能删除同一个 Stream Key 下不同的旧值也正是因为下游算子含物化状态依赖这条链路做状态维护。3.4 源码级的推导逻辑derive_pk存储主键与 Stream Key 的推导集中在 derive.rs 的 derive_pk该函数同时服务于表和 Sink 的建表/建 Sink 流程。其核心逻辑可归纳为四步确定 Stream Key 初值取分布键dist_column_indices若无分布要求则为空并入输入计划的 Stream Key将input.expect_stream_key()去重后追加保证流上可标识用用户 ORDER BY 构造存储主键前缀对user_order_by做函数依赖最小化func_dep.minimize_order_key后逐列加入pk同时维护remaining_stream_key一旦 ORDER BY 列已覆盖全部 Stream Key 列就提前停止对应源码中的stop_order_by_after_stream_key补齐剩余 Stream Key 列将尚未进入pk的 Stream Key 列以升序OrderType::ascending追加到pk尾部。由此可以推出一个重要不变量Stream Key 一定是存储主键的子集stream_key ⊆ pk_columns且存储主键的前缀由用户 ORDER BY 决定、尾部由 Stream Key 补齐——这既保证了排序要求又保证了按 Stream Key 定位后一定能构造出完整的存储键。另外create table场景下pk_column_indices直接来自用户声明的 SQL 主键Stream Key 与表主键一致stream_materialize.rs。3.5pk_conflict写入冲突策略EXPLAIN中的pk_conflict字段对应表目录中的ConflictBehavior它决定了当写入记录与存储主键冲突时的处理方式。从 stream_materialize.rs 可以看到NoCheck默认策略适用于 Append-Only / Retract 流此时系统会拒绝 Upsert 输入reject_upsert_input!保证不会出现主键冲突写入Overwrite、IgnoreConflict、DoUpdateIfNotNull用于 Upsert 流可将 Upsert 流转换为 Retract 流语义后继续处理。在EXPLAIN输出中columns / stream_key / pk_columns / pk_conflict / watermark_columns正是由 stream_materialize.rs 的 distill 实现 逐字段渲染出来的其中pk_columns直接取自table.pk中每个ColumnOrder的列名stream_key取自table.stream_key()对应的列名。四、两类 Key 的协同全景把前面内容串起来RisingWave 中一条记录的生命周期大致是写入/更新到达外部变更进入流携带 Stream Key流式算子维护状态聚合、Join、Top-N 等算子按 Stream Key 索引各自状态依靠 Insert/Delete 交替约束正确回退物化落盘StreamMaterialize节点按存储主键ORDER BY 前缀 Stream Key 补齐把记录写入 Hummock有序读取按分区顺序扫描存储键直接得到满足 ORDER BY 的结果定点更新用 Stream Key 命中记录、取出完整旧值、以存储主键定位并覆盖。这一设计同时满足了三个诉求流上状态一致Stream Key 交替约束、存储上有序存储主键前缀排序、分布均匀可扩展分布键并入 Stream Key。对于下游算子而言Stream Key 是状态寻址的句柄对于存储引擎而言存储主键是排序与定位的目录。五、实践要点速查在EXPLAIN/EXPLAIN (FORMAT JSON|YAML)中查看StreamMaterialize节点时优先核对stream_key与pk_columns若两者不一致说明存在 ORDER BY 参与存储主键、或分布键并入 Stream Key 的情况物化视图的ORDER BY会改变存储主键从而影响状态表在 Hummock 中的物理排序与扫描效率应把最常用的排序/过滤前缀列放在 ORDER BY 前部DISTRIBUTE BY分布键会进入 Stream Key但通常不会成为唯一标识列它影响的是记录的分布亲和性流式计划要求同一 Stream Key 的 Insert/Delete 严格交替且更新必须携带正确旧值任何破坏该约束的上游如非法定制连接器都会导致下游状态错乱带 TTL 的表会自动把 TTL watermark 列追加进 Stream Key以避免过期数据被误判为新插入。对 Key 语义的深入理解能帮助你在排查流式结果错乱、状态膨胀、扫描性能异常等典型问题时第一时间从stream_key/pk_columns中找到根源。更多细节可继续阅读仓库中的设计文档 docs/dev/src/design/keys.md 与前端优化器实现 derive.rs、stream_materialize.rs。赞分享数据库流处理后端数据工程【免费下载链接】risingwaveEvent streaming platform for agentic AI. Continuously ingest, transform, and serve event streams in real time, at scale.项目地址https://gitcode.com/gh_mirrors/ri/risingwave点击查看免费下载相关推荐Matter SDK 示例应用深度解析Qorvo QPG6200 Persistent Storage 应用与 Key-Value 存储 API 验证Matter SDK 示例应用深度解析Qorvo QPG6200 Persistent Storage 应用与 Key Value 存储 API 验证 本篇文物联网智能家居嵌入式通信Milvus 按主键检索Search By Primary Keys / Search by IDs设计与实现深度解析Milvus 按主键检索Search By Primary Keys / Search by IDs设计与实现深度解析 在 Milvus 向量数据库中标准数据库向量数据库分布式数据库后端ToolJet Database 主键Primary Key完整指南单字段、复合主键的创建、修改与删除ToolJet Database 主键Primary Key完整指南单字段、复合主键的创建、修改与删除 ToolJet Database 是 ToolJe低代码后端前端AI 应用MCP 服务上一篇 Integration Task下一篇Aqua构建现代网站和用户系统的开源利器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Apache Beam Python SDK 支持版本管理:新增与移除 Python 版本的完整操作流程

Apache Beam Python SDK 支持版本管理:新增与移除 Python 版本的完整操作流程

大数据批处理流处理数据工程 【免费下载链接】beam Apache Beam is a unified programming model for Batch and Streaming data processing. 项目地址: https://gitcode.com/gh_mirrors/beam4/beam 点击查看 免费下载 Apache Beam 的 Python SDK 需要跟随 Python …

2026/9/25 2:25:07 阅读更多 →
Hunk 的 Jujutsu 后端解析:@hunk/jj 静态捆绑 VCS Provider 的设计与实现

Hunk 的 Jujutsu 后端解析:@hunk/jj 静态捆绑 VCS Provider 的设计与实现

开发工具代码评审CLIAI 应用 【免费下载链接】hunk Review-first terminal diff viewer for agentic coders 项目地址: https://gitcode.com/gh_mirrors/hu/hunk 点击查看 免费下载 Jujutsu(jj)是一款面向 Agent 工作流的现代版本控制系统&a…

2026/9/26 3:55:49 阅读更多 →
反激多路输出电压飘高原因与系统级解决方案

反激多路输出电压飘高原因与系统级解决方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/26 4:55:27 阅读更多 →

最新新闻

OpenClaw安全排查与卸载指南:本地Agent常驻进程风险全解析

OpenClaw安全排查与卸载指南:本地Agent常驻进程风险全解析

最近后台收到不少关于 OpenClaw 的提问,问题高度统一:"我电脑上是不是装了一个叫 OpenClaw 的东西?该不该卸载?它对我的系统安全到底做了什么?"上周帮朋友排查一台 Ubuntu 服务器,发现系统里躺着…

2026/9/26 4:55:24 阅读更多 →
JS蛇簧联轴器源头厂家怎么选?选型安装维护避坑指南

JS蛇簧联轴器源头厂家怎么选?选型安装维护避坑指南

常年混迹各类机械加工厂和成套设备项目的人,应该都听过“蛇簧联轴器”这个名字。它在卷扬、破碎机、皮带机这些重载场合几乎是标配。但你真要去选一家JS蛇簧联轴器口碑好的源头厂家时,会发现水挺深的。市面上挂“源头”牌子的企业不少,真正有…

2026/9/26 4:55:24 阅读更多 →
干了五年后端,我为什么转行了

干了五年后端,我为什么转行了

提交完最后一行代码,我盯着屏幕上闪烁的光标,像是在与一位老友做最后的告别。五年前,我满怀憧憬地踏入后端开发的世界,以为找到了可以奋斗终身的职业方向。然而今天,我却要转身离开。促使我做出这个决定的,…

2026/9/26 4:55:24 阅读更多 →
内核协议解析的C++模糊测试:从环境搭建到崩溃追踪

内核协议解析的C++模糊测试:从环境搭建到崩溃追踪

1. 协议解析代码:为什么它是内核模糊测试的最佳目标1.1 协议解析器比想象中更脆弱如果你在内核开发里待过一段时间,一定见过这种场景:一段解析外部输入的代码,长度字段做了检查,边界条件好像也写了判断,单元…

2026/9/26 4:55:24 阅读更多 →
高并发缓存架构设计与性能优化

高并发缓存架构设计与性能优化

ok,话不多说直接上架构图:缓存击穿避免大量缓存失效,失效时间随机分布。单个缓存失效,并发请求,热点缓存永不过期。redis与mysql数据不一致:读写锁,canal订阅binlog。缓存穿透:布隆过…

2026/9/26 4:55:24 阅读更多 →
具身智能遇上嵌入式操作系统:实时性、异构算力与混合部署实战解析

具身智能遇上嵌入式操作系统:实时性、异构算力与混合部署实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/26 4:54:23 阅读更多 →

日新闻

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、…

2026/9/26 0:00:25 阅读更多 →
学校官网模拟全流程实践:从页面布局到后端接口与部署

学校官网模拟全流程实践:从页面布局到后端接口与部署

如果你正在找一门 Web 大作业的题目,或者刚开始接触 Web 前端开发想做点能拿来展示的东西,“学校官网模拟”几乎是最稳的选择。题目看着简单,但要把导航、新闻列表、轮播 Banner、二级页面、后台数据都串起来,其实已经把前端布局、…

2026/9/26 0:00:25 阅读更多 →
超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

简介:这是一份面向游戏开发初学者与C进阶学习者的超级玛丽(超级马里奥)游戏源码,基于C面向对象编程实现,适合想通过经典项目理解游戏主循环、角色类设计、地图关卡加载与物理碰撞检测的读者参考。压缩包共49个文件&…

2026/9/26 0:00:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/25 19:27:14 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/25 11:15:26 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/25 20:29:09 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/25 20:29:43 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/25 20:29:31 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/25 19:27:26 阅读更多 →