首页/新闻资讯/正文详情

PRQL 语言设计哲学:从“翻译成 SQL“走向“以关系为中心“的思考方式

发布时间:2026/9/24 1:14:31 来源:云帆数科 栏目:资讯中心
PRQL 语言设计哲学:从“翻译成 SQL“走向“以关系为中心“的思考方式
后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载PRQL 是一门面向数据转换的现代语言其编译器本质上是把 PRQL 翻译成 SQL 的转译器但官方语言设计指南明确指出语言设计绝不能以这个特性怎么翻译成 SQL为出发点而应以这个特性如何作用于关系relation为中心。本文以 language-design.md 为核心骨架结合 prqlc 编译器的真实源码与测试剖析这一设计原则的来龙去脉帮助你建立正确的 PRQL 语言设计视角——无论你是想为 PRQL 提交新特性提案还是想深入理解编译器内部如何把一条条流水线翻译成最终 SQL。一、背景PRQL 首先是一个转译器PRQL 在项目中的定位是SQL 的流水线式替代品a simple, powerful, pipelined SQL replacement。在实现层面它确实是一个把 PRQL 文本编译成 SQL 文本的转译器prqlc提供的顶层入口 compile 函数 接收一段 PRQL 字符串依次经过prql_to_pl解析成 PL AST、pl_to_rq语义分析与降级、rq_to_sql生成 SQL三个阶段后返回 SQL 字符串。正因为最终要产出 SQL这一事实如此显眼语言设计很容易滑向一种以 SQL 为中心的思维惯性把每个 PRQL 特性都先想象成它对应哪段 SQLPRQL feature - SQL feature - relational result官方语言设计指南明确指出这种思路是有缺陷的原因有两点它无法很好地建模特性之间的交互。两个特性单独看都能翻译成合理的 SQL但当它们组合在一起时翻译结果可能出现语义偏差而逐个特性翻译的思维框架根本看不到这一点SQL 行为本身有时具有误导性甚至在不同方言之间不一致。例如子查询中的排序不会在父查询中保留集合运算UNION、INTERSECT、EXCEPT在方言之间也存在行为差异。二、为什么以 SQL 为中心是错的来自源码的佐证2.1 特性交互sort、group、join的组合陷阱官方文档指出它不能很好地建模特性之间的交互。仓库里恰好有一个回归测试可以当作活教材。在 lib.rs 的test_sort_not_propagated_after_join测试中注释直接引用了 PRQL 规范Per PRQL spec,groupresets the order. Thesortinside a group is for row selection (which row to keep), not output ordering. After the group, there is no defined order, so it should not appear in the outer query.翻译过来按照 PRQL 语义group会重置排序group内部的sort只用于选哪一行保留即行选择而不是输出排序group之后没有定义好的顺序所以它不应该泄漏到外层查询。看这条测试对应的 PRQL 与生成 SQL 的对照prql target:sql.postgres from tracks group media_type_id ( sort name take 1 ) join media_types ( media_type_id) select { tracks.track_id, media_types.name }生成的 SQL 中sort name只出现在 CTE 内部的DISTINCT ON行选择逻辑里外层JOIN之后的 SELECT 没有任何ORDER BYWITH table_0 AS ( SELECT DISTINCT ON (media_type_id) track_id, media_type_id, name FROM tracks ORDER BY media_type_id, name ) SELECT table_0.track_id, media_types.name FROM table_0 INNER JOIN media_types ON table_0.media_type_id media_types.media_type_id而 同文件中的另一个测试test_explicit_sort_after_distinct_on_preserved则验证了相反的情况如果用户在group之后显式sort media_type_id这个新引入的顺序就应该穿透join一直传播到最终输出。这两条测试一正一反正是特性交互必须用关系语义来定义、而不能靠逐个翻译 SQL 来凑的绝佳证据——如果设计者脑子里只有sort → ORDER BY这一条映射就根本无法回答group内的 sort 和group外的 sort 到底该落在生成的哪一层。2.2 SQL 行为的误导性子查询的顺序不会保留官方文档指出SQL 行为有时会误导人子查询中的顺序不会在父查询中保留。这可以从编译器的 RQRelational Query中间表示中得到印证在 RQ 层面排序是关系的一种显式属性Sort是关系变换列表中的一个独立变换而在 SQL 层面子查询里的ORDER BY只有在LIMIT/OFFSET伴随下才有确定语义一旦进入父查询子查询的排序约定就会丢失。因此编译器不能在翻译到最后一步之前就依赖 SQL 子查询的排序行为而必须在语义层先把顺序表达为关系上的确定属性再由 SQL 生成阶段决定把它物化到哪里CTE、窗口函数还是最外层ORDER BY。2.3 方言差异集合运算与DISTINCT ON官方文档还指出 SQL 行为在不同方言之间不一致集合运算。prqlc 对此的应对是把方言相关的决策尽量推迟到编译管线最末端的 SQL 后端阶段而不是让语言语义去迁就某个方言。仓库中的 sql/dialect.rs 定义了Dialect与SupportLevel枚举SQL 后端针对不同方言采用不同的生成策略例如上面测试里出现的DISTINCT ON就是 PostgreSQL 方言特有的写法它只在target:sql.postgres下才会被生成其他方言会走各自的等价实现。语言本身不关心这些差异——关系语义只有一个方言差异是最后一公里的事。三、正确的视角PRQL 特性作用于关系官方文档给出了替代方案我们应该思考 PRQL 特性如何影响 PRQL 表达式——在绝大多数情况下也就是如何影响关系PRQL feature - relation | v PRQL feature - relation | v PRQL feature - relation | v relational result这条流水线式的图示与 PRQL 语言本身的形态完全同构PRQL 的一条查询就是由from、select、filter、group、join等变换transform构成的管线每一个变换都接收一个关系、产出一个新关系最终得到关系结果。语言特性比如sort、take、window首先应该被理解为对当前关系的某种操作而不是对 SQL 的某种翻译。3.1 源码中的关系RQ AST这条原则在编译器中间表示里体现得极为直接。RQRelational Query是编译器在语义分析后得到的严格类型化、用于描述关系查询的 AST见 ir/rq/mod.rs。其核心结构是RelationalQuery由def查询定义、tables表声明集合与relation主关系组成Relation包含kind与columns列定义即该关系对外暴露的接口RelationKind关系的种类其中Pipeline(VecTransform)表示一条由多个变换组成的关系管线。而变换本身是一组封闭的、与 SQL 无关的语义操作见 ir/rq/transform.rs 中的Transform枚举pub enum Transform { From(TableRef), Compute(Compute), Select(VecCId), Filter(Expr), Aggregate { partition: VecCId, compute: VecCId }, Sort(VecColumnSortCId), Take(Take), Join { side: JoinSide, with: TableRef, filter: Expr }, Append(TableRef), Loop(VecTransform), }注意这里没有任何SELECT 关键字ORDER BY 子句之类的 SQL 词汇——Filter、Sort、Take、Aggregate、Join描述的都是对关系的变换这正是PRQL 特性 → 关系原则在实现层的直接体现。3.2 语义层的关系状态Lineage谱系在语义分析阶段PL 层面编译器为每一个变换维护当前关系的完整描述这就是 ir/pl/lineage.rs 中定义的Lineage。它的文档注释写得很直白Represents the object that is manipulated by the pipeline transforms. Similar to a view in a database or a data frame.——表示被管线变换所操作的对象类似于数据库中的视图或一个数据框。Lineage 记录了当前关系的列集合每个列要么是Single单个列带有名字与定义它的表达式 id要么是All来自某个输入的整组列支持except排除集对应foo_table.*语法。语义解析器semantic/mod.rs 中的resolve在逐条处理语句时会同步更新这个 Lineage——一个变换作用于关系、产生新关系然后下一个变换再作用于这个新关系这与官方文档第二张图的链条完全一一对应。3.3 从源码注释到设计共识在 lowering.rs 的模块注释中编译器明确写下了降级PL → RQ过程要保证的语义不变量transforms 不会被嵌套每个变换都是关系层面的一层操作transforms 具有正确的 partition、window 与 sort 设置不存在未解析的表达式。这组不变量本质上就是以关系为中心的工程化落地语言特性必须在语义层就被规范化成对关系的确定操作而不是把问题留给 SQL 生成阶段去碰运气。四、SQL 只在最后一步介入官方文档的结论是只有在最后一步——当关系或者说关系表达式被翻译成 SQL 表达式时——才需要开始思考 SQL。这一论断与 prqlc 的编译架构ARCHITECTURE.md完全吻合。编译器划分为三大阶段阶段子阶段使用的 ASTparselexer / parserLRLexer Representation→ PRParser Representationsemanticast_expand / resolver / flatten / loweringPR → PL → RQsqlpreprocess / pq-compiler / postprocess / sql-compiler / codegenRQ → PQ →sqlparser::ast→ string三个阶段里只有最后一个sql阶段才接触 SQL。semantic阶段的全部工作名称解析、声明提取、类型推断、Lineage 计算、PL 降级为 RQ都不依赖任何 SQL 概念RQ 之后sql/mod.rs 的compile函数才接手把 RQ 中的每个关系转换为一个 SQL 查询把管线在合适位置切分成可以用单个 SELECT 表达的小段即AtomicPipelines最后按方言生成文本。这带来了一个重要的实践含义语言设计者在思考新特性时应当先在关系这一层把语义定义清楚SQL 只是最后的表达手段。只要关系语义是确定的、自洽的无论最终要适配哪个 SQL 方言、是生成 CTE 还是嵌套子查询都只是sql阶段的技术决策而不会反过来推翻语言设计。4.1 一个例子名称解析的最后一公里参考文档 name-resolution.md 的 Translating to SQL 一节是这条原则的绝佳注脚PRQL 的作用域规则完全是关系层面的——from或join引入的表会作为命名空间注入作用域命名空间里是该表的所有列此外还有一个无名的特殊命名空间frame装着当前变换正在操作的关系的列。至于生成的 SQL 里列名要不要带表前缀完全是 SQL 翻译层的决定当查询只引用一张表时不需要前缀select first_name直接生成SELECT first_name当存在多张表且无法确知所有列归属时才给所有列名加上表前缀以防歧义。也就是说有没有前缀是 SQL 生成阶段根据歧义风险做出的工程取舍并不改变 PRQL 语言本身的语义——语言层面first_name始终通过作用域解析到唯一确定的列。五、把原则落到实践评估一个新 PRQL 特性把官方设计指南转化为可操作的设计流程大致如下问关系层面的问题这个特性输入一个关系时输出什么关系它改变列如derive、select、改变行如filter、take、改变分组与聚合状态如group、aggregate还是改变顺序如sort它和前后相邻的变换如何组合用 PRQL 语义先定义清楚例如group内sort只用于行选择、不决定输出顺序这是关系语义层的规定详见 group 标准库文档 与相关回归测试最后才考虑 SQL 表达这个关系语义在目标方言下如何落地是直接映射、用 CTE还是需要拆分管线如窗口函数在 WHERE 子句中无法物化时触发拆分见 ARCHITECTURE.md 中关于 anchoring 的说明用反例检验如果按逐特性翻译成 SQL的思路会得出错误组合结果说明这个特性还没有被定义清楚应该回到关系层面继续推敲。六、参与 PRQL 语言设计的正确姿势如果你希望亲自参与 PRQL 的语言设计仓库的贡献指南给出了一套与本文原则呼应的做法新语言特性在 GitHub issue 中决策通常挂有language-design标签讨论的核心就是这个特性如何作用于关系这类语义问题而不是 SQL 怎么写发现编译器产生错误结果时提交 bug 报告可以使用仓库内的 playground 前端web/playground目录快速复现查询并导出生成 SQL收集难以用 PRQL 表达的查询示例尤其是比 SQL 更难表达的情况并贴到相关 issue 中——官方强调脱离示例的建议很难被认真对待任何建议都应当锚定在具体示例上想动手写编译器代码的话可以沿 development.md 与 ARCHITECTURE.md 入手编译器prqlccrate位于 prqlc/prqlc用 Rust 编写其 PL/RQ 中间表示正体现了本文所述的设计思想。七、总结PRQL 语言设计指南的核心只有一句话把每个特性想成对关系的操作而不是对 SQL 的翻译。以 SQL 为中心的视角会遮蔽特性间的交互、被 SQL 本身的误导性行为带偏、并且无法统一处理方言差异而以关系为中心的视角让语言语义保持自洽SQL 只在编译管线的最末端作为表达手段登场。prqlc 的架构PL 语义层维护 Lineage、RQ 用Pipeline(VecTransform)描述关系变换、SQL 后端在最后阶段才处理方言与物化策略正是这一设计哲学的工程实现。带着这个视角去阅读 language-design.md、去 review 新的语言特性提案你会发现 PRQL 的设计讨论始终围绕一个清晰的问题展开这个特性让关系发生了怎样的变化赞分享后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载相关推荐english-note哲学语言与思维关系english note哲学语言与思维关系 还在为英语语法头疼不已每次看到复杂的语法规则就望而却步english note项目通过独特的哲学视角揭示了语文档知识库教程终极指南从Python到Elixir的编程语言设计哲学解析终极指南从Python到Elixir的编程语言设计哲学解析 编程语言哲学是开发者理解代码世界的钥匙。不同的语言设计思想不仅影响着代码的编写方式更塑造了程序员文档教程技术博客知识库VideoMAE模型库全面解析从ViT-S到ViT-H的性能对比与应用场景VideoMAE模型库全面解析从ViT S到ViT H的性能对比与应用场景 VideoMAE是NeurIPS 2022 Spotlight收录的创新视频自监督深度学习计算机视觉创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

降维打击!大厂面试官逼我手撕 qsort,我却顺手搞懂了 AI 框架底层
降维打击!大厂面试官逼我手撕 qsort,我却顺手搞懂了 AI 框架底层

开场白:从“调包侠”到“底层狂魔”的阵痛去大厂面试 C/C 岗位,如果面试官让你写个排序,你直接秒答 qsort(arr, n, sizeof(int), cmp);,大概率会收获一句礼貌的“回去等通知”。为什么?因为调库只能证明你会用 API&… · 2026/9/24 1:14:19

同轴电缆衰减特性全解析:从原理到工程实测与选型
同轴电缆衰减特性全解析:从原理到工程实测与选型

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

RNS510车载系统固件更新与功能扩展实战指南
RNS510车载系统固件更新与功能扩展实战指南

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

罗技G304使用指南:续航、灯光与省电技巧全解析
罗技G304使用指南:续航、灯光与省电技巧全解析

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

从S19到Dshot:EFM8BB21F16G电调刷BLHeli_S固件全攻略
从S19到Dshot:EFM8BB21F16G电调刷BLHeli_S固件全攻略

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

齿科3D打印落地指南:光固化设备、材料与流程全解析
齿科3D打印落地指南:光固化设备、材料与流程全解析

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

PaddleHub vgg13_imagenet 图像分类模块:基于 VGG13 与 ImageNet-2012 的安装、预测 API 与实现原理详解
PaddleHub vgg13_imagenet 图像分类模块:基于 VGG13 与 ImageNet-2012 的安装、预测 API 与实现原理详解

人工智能大模型微调模型推理服务 【免费下载链接】PaddleFormers PaddleFormers is an easy-to-use library of pre-trained large language model zoo based on PaddlePaddle. 项目地址: https://gitcode.com/gh_mirrors/pa/PaddleFormers 点击查看 免费下载 导读… · 2026/9/24 1:51:10

EMC设计全链路实战:从原理图到量产的硬核避坑指南
EMC设计全链路实战:从原理图到量产的硬核避坑指南

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

STM32H7 OSPI+PSRAM内存映射实战:MPU配置与时序避坑指南
STM32H7 OSPI+PSRAM内存映射实战:MPU配置与时序避坑指南

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

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码