“多重集分组聚合继续保留这些重复贡献,逐项定义 COUNT、SUM 与 AVG。它用一组有重复行的订单与标签证明:提前聚合必须保留连接键,而平均值需要携带 sum/count 状态,不能只平均…”
形式陈述 ​
重复行也是查询输入 ​
集合关系代数只记录一行是否出现。多重集关系(bag)还记录它出现多少次:对每个元组
本页固定有限 bag、相等连接和精确有理数数值列,不包含 NULL、排序、外连接、窗口或 DISTINCT 聚合。自然连接将匹配行的重数相乘;投影将落入同一输出行的重数相加。这与查询来源的自然数标注相符,但本页要进一步把重数用于计算结果列中的数值。
给定分组键
普通按键分组对每个
输出行的重数为一。列中的
可合并状态与空组 ​
为一个分组保存状态
单位状态为
按显式键分组时,空输入没有出现过的键,结果为空。全局聚合则约定只有一个空键,即使输入为空也输出状态
直觉
连接把匹配事实配成对。若一条订单出现两份、与它匹配的标签也出现两份,就有四个订单—标签配对;每个配对都参与聚合。列值相同不意味着这些贡献可以悄悄合并成一份。
分组是把相同键的贡献收集到一起。COUNT 统计贡献份数,SUM 累计每份的数值,AVG 把这两个量相除。例如金额
提前聚合可以减少连接中反复处理的行,但摘要必须保存后续仍会用到的信息。连接键决定去找谁,分组键决定最后算进哪一组,
例子与边界
两张有重复行的表 ​
订单表 Orders(Customer, Product, Amount) 如下。最后一列是 bag 重数,金额采用精确整数;它不是价格乘数量的业务规则,而是明确表示输入中这条元组有几份。
| Customer | Product | Amount | 重数 |
|---|---|---|---|
| A | p | 10 | 2 |
| A | p | 30 | 1 |
| A | q | 100 | 1 |
| B | p | 20 | 1 |
| B | q | 50 | 2 |
| C | r | 7 | 1 |
标签表 Tags(Product, Tag) 为:
| Product | Tag | 重数 |
|---|---|---|
| p | sale | 2 |
| p | featured | 1 |
| q | sale | 1 |
| q | featured | 3 |
查询按 Product 连接,再按 (Customer, Tag) 分组,计算订单金额的 COUNT、SUM、AVG。两表在 Product 上都不要求唯一;正是多对多匹配让重复计数成为核心问题。
展开全部连接贡献 ​
连接中的每行重数等于两条输入重数之积:
| Customer | Product | Amount | Tag | 连接重数 |
|---|---|---|---|---|
| A | p | 10 | sale | 4 |
| A | p | 10 | featured | 2 |
| A | p | 30 | sale | 2 |
| A | p | 30 | featured | 1 |
| A | q | 100 | sale | 1 |
| A | q | 100 | featured | 3 |
| B | p | 20 | sale | 2 |
| B | p | 20 | featured | 1 |
| B | q | 50 | sale | 2 |
| B | q | 50 | featured | 6 |
十种不同元组代表
A/sale 这一组包含四份金额
| Customer | Tag | COUNT | SUM | AVG |
|---|---|---|---|---|
| A | sale | 7 | 200 | |
| A | featured | 6 | 350 | |
| B | sale | 4 | 140 | |
| B | featured | 7 | 320 |
四个计数之和为
用摘要重做同一个查询 ​
先按 (Customer, Product) 汇总 Orders,保留连接列 Product:
| Customer | Product | ||
|---|---|---|---|
| A | p | 3 | 50 |
| A | q | 1 | 100 |
| B | p | 1 | 20 |
| B | q | 2 | 100 |
| C | r | 1 | 7 |
摘要遇到重数为
结果与展开连接完全相同。C/r 的摘要找不到标签,仍没有贡献。这里使用相同数据完成两种执行方式,下一节的有限和证明则保证它们对整个模型都等价。
三种看似省事、实际改变结果的改写 ​
把重复元组去掉。 若在完整连接后做 DISTINCT,A/sale 只留下金额
只携带平均值。 A/p 的部分平均是
与正确的
过早丢掉 Product。 比较两份单行 Orders:一份是
推论与应用
连接之前聚合的精确条件与证明 ​
设
定义两侧摘要
那么每个最终组满足
证明从原始连接的重数开始。计数为
SUM 在同一求和中多乘一个金额
所有支撑有限,重排和分配都合法,不涉及极限或绝对收敛。对于显式键分组,
若
这说明一种正确的执行方式:先把 R 按
与集合查询、来源和执行代价的边界 ​
这份改写要求后续操作只读取留下的键和摘要。若过滤条件还要判断原金额是否大于某个阈值,就应先在原数据上过滤,或另外证明摘要足以支持该判断。上面的等式也不直接处理 DISTINCT AVG、外连接补行或 NULL 的三值语义。
COUNT/SUM 可通过加法合并部分状态,AVG 则需要固定大小的
查询来源中的自然数标注解释了为什么连接乘重数、投影加重数;聚合又把金额与重数结合,生成新的数值列。因此这里没有宣称原来的来源多项式通用求值定理已覆盖任意聚合。经典关系代数与演算的集合表达力等价也保留原来的不含聚合范围。
正确下推可以压缩重复贡献,但是否更快取决于分组数量、摘要大小和连接实现。若每条输入都带不同的
终点自测:从两张输入表重建十种连接元组及其
参考资料
- Todd J. Green, Grigoris Karvounarakis, and Val Tannen, “Provenance Semirings”, PODS 2007, pp. 31–40,§3,Definitions 3.1–3.2,p. 33:有限支撑关系、自然数 bag 标注与连接乘法、投影加法。
- Jim Gray et al., “Data Cube: A Relational Aggregation Operator Generalizing Group-By, Cross-Tab, and Sub-Totals”, Data Mining and Knowledge Discovery 1, 1997, pp. 29–53,§5,pp. 48–49:分布型与代数型聚合,AVG 的 sum/count 合并状态。
- Surajit Chaudhuri and Kyuseok Shim, “Including Group-By in Query Optimization”, VLDB 1994, pp. 354–366,§2.3,pp. 356–357;§§3.2–3.4,pp. 358–361:提前分组保留的列、部分聚合与 Group-Count。本页独立证明明确有限 bag 模型中的两侧摘要恒等式。
- PostgreSQL Documentation, Aggregate Functions,§9.21,聚合表后的空输入说明:COUNT 返回零,其他多数聚合包括 SUM 在空输入上返回 NULL。仅用于比较 SQL 与本页数学空和约定。