Skip to content

算法Algorithm

最坏情形最优连接

Worst-case optimal joins · WCOJ

从AGM熵界到一般NPRR锚关系递归,完整核算三角形和四三元表实例的枚举与索引成本。

形式陈述 ​

全连接与分数边覆盖 ​

固定一个输出全部变量的合取查询。用有限属性集 V 和带索引的属性族 (ei)i∈I 表示它:V=⋃iei,每张输入表 Ri 是属性 ei 上的有限元组集合,大小为 Ni。这是超图的关联表示;即使两张表使用相同属性集,也保留不同的索引,不把两项约束合并。自然连接为

J={t 为 V 上的元组:t|ei∈Ri 对每个 i∈I}.

若原查询的原子含常量或重复变量,先逐个原子规范化:扫描它对应的原始关系,只保留常量位置匹配、同一变量的所有位置取值相等的记录,再投影为每个不同变量各一列的集合 Ri。例如 S(x,c,x) 只保留第二列等于 c、第一列等于第三列的记录,规范化后只有属性 x。同一关系符号的不同原子仍有各自的索引和筛选条件。没有变量的原子得到零列表:存在匹配事实时为 {()},否则为空集。这样,每份完整变量赋值满足原子,当且仅当其属性投影属于相应的 Ri,故规范化保持查询答案。

以下的 Ni=|Ri| 与 AGM 预算均针对规范化后的表。固定查询下,若从原始表开始执行,还须计入扫描、筛选与集合投影的预处理;在本页的字与哈希成本模型中,这部分期望时间与各原子所读原始表的行数总和成正比。后文 O(∑iNi+U) 的输入规模保证以已经规范化的表为起点。

这里没有 NULL、重复计数或额外依赖约束。任何输入表为空时,直接返回空集。以下设 Ni≥1。一组非负权重 xi 是分数边覆盖,若每个属性收到的总权重至少为一:

xi≥0,∑i:v∈eixi≥1(v∈V).

AGM 界断言,对每个这样的覆盖,都有

|J|≤∏i∈INixi.

因此,令 U 为右端在全部分数覆盖上的最小值,便得到只依赖查询结构和各表大小的输出上界。求 U 等价于下列线性规划:

minx∑ixilog⁡Ni满足上述覆盖约束,U=exp(minx∑ixilog⁡Ni).

本页所有对数均为自然对数,熵也使用自然对数定义;exp 是其逆函数。大小不等时,目标不是无权的 ∑ixi。

“最坏情形最优”的量词 ​

连接算法若在固定查询下,以 O(∑iNi+U) 的时间完成预处理并枚举答案,就达到了按这些输入大小衡量的最坏情形保证。随机哈希实现的时间应理解为期望时间。其依据是:存在输入使输出本身已达到该界的查询相关常数倍,任何逐条输出算法都必须付出相应时间。它不表示算法在每一份具体实例上都最快,也不表示耗时总与实际输出 |J| 成正比。

本页先证明三角形的两分支规则,再展开一般 NPRR 的锚关系递归、正确性与固定查询成本。一般执行使用切片计数选择局部分支,不把三角形阈值直接套在任意超图上。

直觉

一张表约束它所涉及属性的联合取值。三角形查询中,每个属性被两张表约束,给每张表半份权重,便恰好覆盖每个属性一次。输出元组若很多,其联合不确定性就大;但每张输入表都限制了一部分不确定性,覆盖权重把这些限制合成为总输出的上界。

执行算法面临的是另一件事:先连接两张表,可能暂时枚举许多最终会被第三张表否决的组合。共享值的度数很大时,这一步尤其昂贵。重轻分解对高度数值改从第三张表出发,对低度数值才展开二元连接,从而把两种不同的枚举成本配平。

例子与边界

三角形的精确证书与达到上界的输入 ​

取

J=R(A,B)⋈S(B,C)⋈T(A,C),(|R|,|S|,|T|)=(r,s,t).

覆盖约束是 xR+xT≥1、xR+xS≥1、xS+xT≥1。三个整覆盖 (1,1,0),(1,0,1),(0,1,1) 与半覆盖 (1/2,1/2,1/2) 分别给出四个界,而且最优值恰为

U=min{rs,rt,st,rst}.

这不只是列出四个可行解。令 a=log⁡r,b=log⁡s,c=log⁡t。若 a≥b+c,任一覆盖的代价满足

axR+bxS+cxT≥b(xR+xS)+c(xR+xT)≥b+c,

整覆盖 (0,1,1) 达到它。另两个超长边情形同理。剩下的情形满足三角不等式;置

yA=(a+c−b)/2,yB=(a+b−c)/2,yC=(b+c−a)/2.

它们非负。将三个覆盖约束分别乘以 yA,yB,yC 再相加,任一可行代价至少为 (a+b+c)/2,而半覆盖达到它。这就穷尽了全部大小组合,包括某张表只有一行的边界。

令 X,Y,Z 都有 k 个值,取 R=X×Y,S=Y×Z,T=X×Z。三张表各有 N=k2 行,连接恰为 X×Y×Z,共有 k3=N3/2 行。因此等大输入的指数 3/2 不能降低。非平方或任意指定大小未必精确取等;一般 AGM 紧性结论允许一个仅依赖查询的常数因子。

三角形的重轻枚举 ​

令 R[b]={a:(a,b)∈R},S[b]={c:(b,c)∈S},记 dR(b)=|R[b]|。选阈值 τ>0,定义重值集合 D={b:dR(b)>τ}。以下伪代码使用集合成员索引,并按 B 分组;阈值可以是实数,直接与整数度数比较。

text
Triangle(R, S, T):
    if any input is empty: return
    build membership indexes for R, S, T
    group R and S by their B coordinate
    tau = sqrt(|R| * |T| / |S|)
    D = {b in keys(R): |R[b]| > tau}

    for b in D:                         # 重值:从第三张表出发
        for (a, c) in T:
            if (a, b) in R and (b, c) in S:
                emit (a, b, c)

    for b in keys(R) with b not in D:    # 轻值:展开受控的二元连接
        for a in R[b]:
            for c in S.get(b, empty):
                if (a, c) in T:
                    emit (a, b, c)

每个输出的 b 恰好属于一个分支。重分支遍历其必需的 T 元组再核验另外两项;轻分支直接枚举 R,S 的匹配再核验 T。因此既不漏报,也没有跨分支重复;集合输入保证每个分支内部同样不重复。

因为 |D|τ≤∑b∈DdR(b)≤r,重分支的候选数至多 rt/τ。轻分支的候选数满足

∑b∉DdR(b)|S[b]|≤τ∑b|S[b]|=τs.

取 τ=rt/s,两项分别至多 rst,合计至多 2rst。若要达到大小不等时的 U,先比较四个代价值:半覆盖最小时用以上算法;否则枚举相应两张表的笛卡尔积,检查共享坐标相等及第三张表的成员关系。后三种方法分别至多检查 rs,rt,st 个候选。无需把四种算法都运行一次。

16 行输入为什么产生 72 与 24 ​

在每张表的两个属性位置放入同一个对称星形关系

E={(0,i),(i,0):1≤i≤8},R=S=T=E.

每张表有 16 行。先做任意一对二元连接时,共享值 0 产生 8⋅8=64 个元组,八个叶值各产生一个,共 72 个。最终答案却为空:星形图没有三角形;具体地,两步路径的两端要么都是叶子,要么都是 0,都不属于第三张表。

重轻算法取 τ=16=4,唯一重值是 0。重分支枚举 D×T 的 16 个候选;每个轻值只有一条 R 记录与一条 S 记录,轻分支共枚举 8 个。总共 24 个候选,最后全部拒绝。一个候选可能执行两次成员查询,这个数不是哈希探测总数。

把 8 换成 k,三张表大小 N=2k,任意第一步二元连接都有 k2+k=Θ(N2) 行,最终仍为空。当 k>2 时,阈值 2k 仍把中心单独列为重值,这个分解只产生 2k+k=3k 个候选。于是差距随着规模增长,不只是一次 72 与 24 的数值比较。这说明仅选定二元连接次序、物化其中间结果不能保证三角形的 O(N3/2) 界;它没有排除额外使用半连接、索引或多路过滤的执行器。

一般 NPRR:按锚关系拆分属性 ​

下面展开原始 NPRR 的边顺序递归,而非把逐个属性的 Generic Join 改名为 NPRR。[4, Algorithms 2–4、Procedure 5] 先固定边顺序 e1,…,em。对当前属性块 U 和前 k 张表,以 ek 为锚,拆成

W=U∖ek,Z=U∩ek.

V=∅ 时先单独处理:每张零列表只有空集或 {()} 两种可能,检查全部表后返回空集或 {()},成本为 O(m+1);没有输入表时按空合取返回 {()}。以下计划树及显式查询因子均限于 m,n≥1。

查询计划树的左子问题是 (W,k−1),右子问题是 (Z,k−1)。空属性块不建节点;若一个块不与前面的任何边相交,也不再建子树。若 U 包含于每个 ei(i≤k),就停止为叶子。其余情况继续拆分。树只依赖查询,不依赖数据;每层属性块两两不交、每条路径的 k 严格下降,所以节点数 H≤mn。

按左块在前、右块在后的顺序输出属性;没有右子树时仍输出只由锚覆盖的剩余属性。这给出一个全局次序,使每个递归属性块连续。每张表按这个次序的限制建立前缀索引,支持三种操作:前缀是否存在;固定前缀后某段属性投影有多少个不同元组;枚举该投影。计数存在索引中,不为每次询问重新扫描原表。用原文的哈希索引实现,可在 O(n2∑iNi) 期望时间内完成预处理;一次访问至多处理 n 个属性。[4, §5.3.2]

记 Ri[s] 为把已赋值属性限制为 s 后、删去这些属性所得的切片。一次调用处理 (U,k,y,s):y1,…,yk 覆盖 U,s 是全局次序中 U 之前属性的固定取值。其任务是求各切片在 U∩ei 上投影的连接。只涉及已赋值属性的约束也要检查:它的零列投影为真关系 {()} 或空关系,不能把空关系当成没有约束。

text
Join(U, k, y, s):
    检查前 k 张表的相关切片投影;若有空集,返回空集
    若 U 为空,返回 {s}
    若 U 包含于每个 e_i (i <= k):
        枚举最小的 U 投影,只保留属于其余全部投影的元组
        返回它们与 s 的拼接

    W = U \ e_k; Z = U ∩ e_k
    L = {s} 若 W 为空,否则 Join(W, k-1, y[1:k-1], s)
    若 Z 为空,返回 L
    q = 锚关系 R_k[s] 在 Z 上的投影大小

    对每个 (s,w) in L:
        A_i = R_i[(s,w)] 在 Z ∩ e_i 上的投影 (i < k)
        若某个 A_i 为空,跳过本前缀
        alpha = y_k
        若 alpha < 1,计算 p = product_i |A_i|^(y_i/(1-alpha))
        若 alpha < 1 且 p < q:
            递归 Join(Z, k-1, y[1:k-1]/(1-alpha), (s,w))
            用锚关系的 Z 投影过滤递归答案
        否则:
            枚举锚关系的 Z 投影,用所有 A_i 过滤
        输出通过过滤的完整拼接

零权重对应的因子为一;先拒绝空切片,再计算乘积,因此无需把 00 当成有效成本。比较相等时扫描锚关系,只有严格 p<q 才递归。覆盖权重作为查询输入,预算比较沿用算术成本口径;固定有理权重时也可清分母比较整数幂,不依赖浮点近似来决定分支。

递归调用确实有合法覆盖。W 中的属性不属于 ek,所以删掉 yk 后仍被覆盖。对 z∈Z,若 α<1,

∑i<kz∈eiyi1−α≥1−α1−α=1.

若某个 Z 属性只由锚覆盖,必有 α≥1,算法直接扫描锚,不会调用不存在的右子树。

正确性按树归纳。叶子求的是集合交;内部节点中,任何完整答案的 W 投影必在左侧结果 L 中。固定该前缀后,它的 Z 部分既满足全部 Ai,也属于锚投影。两种分支都恰好枚举其中一边、检查另一边,故无漏报也无误报。不同 w 对应不同完整元组,集合索引内没有重复,因此不会重复输出。根调用没有尚未处理的属性,返回的正是完整连接;中间的投影连接只保证包含所有能延伸为最终答案的前缀,并不声称每个前缀都能延伸。

非三角超图的两层分支 ​

取四张三元表

R1(B,C,D),R2(A,C,D),R3(A,B,D),R4(A,B,C).

每张表在其显示的列顺序上都使用七个元组

F={000,100,200,010,020,001,002}.

每个属性出现三次,故 xi=1/3 是覆盖。将四条覆盖约束相加得 3∑ixi≥4,所以等大表的最优证书是 U=74/3。这是四维 Loomis–Whitney 查询;它不是三角形,也不是一般超图的穷举代表,算法的普适性来自上一节的递归证明。

按上面的边顺序,根的锚为 R4,先处理 W={D},再处理 Z={A,B,C}。左侧三个一列投影都是 {0,1,2},扫描最小投影产生三个前缀。固定 D 后,前三张表变成三角形的三个二列切片;根的锚预算始终为 q=7。

前缀 三个二列切片大小 右侧覆盖 预算 p 与 q 动作与结果
D=0 都为 5 各 1/2 53/2>7 扫描 R4 的七行,全部通过
D=1 都为 1,内容为 {00} 各 1/2 1<7 递归三角形,得到 ABC=000
D=2 都为 1,内容为 {00} 各 1/2 1<7 同上,得到 ABC=000

后两次递归的锚是 AB 表,先求三个变量中剩余的 C,只有 C=0。此时另外两个一列切片大小都为一,预算 p=q=1,按相等分支扫描一行锚。完整输出按 ABCD 顺序为

0000, 1000, 2000, 0100, 0200, 0010, 0020, 0001, 0002.

枚举循环共执行 3+7+2(1+1)=14 次;其中根的最终扩展候选只有 7+1+1=9 个。两种计数都不是哈希探测总数:每个候选还要做成员检查,预算计算也会读取切片计数。

任意两张原表先二元连接时,共享的两个坐标为 00 会产生 3⋅3=9 个组合;共享坐标中的四个非零单点各贡献一行,总共 13 行。将取值 1,2 扩展到 1,…,h,有

N=1+3h,|J|=1+4h,|Ri⋈Rj|=h2+4h+1.

上述 NPRR 执行的枚举循环为 (h+1)+(1+3h)+2h=6h+2 次。因为 (1+2h)3/2>1+3h(平方后差为 3h2+8h3>0),D=0 始终走扫描锚分支,正值始终递归。这给出了随规模增长的成本差,而非仅在七行输入上的巧合。

集合、投影与约束的边界 ​

若每张表包含同一匹配二元组的 N 份副本,bag 连接有 N3 个输出出现次数。集合 AGM 界约束的是不同完整元组,不能套在这个重复次数上。若查询投影掉部分变量,完整见证的数量仍受本页界约束,但可能远大于去重后的答案数,因此这里没有证明投影查询按实际答案规模最优。

键约束、函数依赖或已知度数分布会缩小允许实例的范围,可能给出更强的界。AGM 使用的只是表大小和属性覆盖;上面的无三角形星形实例也表明,它通常不是单个实例的精确输出预测。

推论与应用

用条件熵证明一般 AGM 界 ​

若 J 为空,结论立即成立。否则从 J 中均匀抽一个完整元组 XV,于是 H(XV)=log⁡|J|。按某个固定次序把属性写成 v1,…,vn,记 X<j=(Xv1,…,Xvj−1)。使用条件熵的链式法则与“增加条件平均不增熵”,对每个 ei 有

H(Xei)=∑j:vj∈eiH(Xvj∣Xei∩{v1,…,vj−1})≥∑j:vj∈eiH(Xvj∣X<j).

乘以非负的 xi 后求和,换序并使用覆盖约束,得到

∑ixiH(Xei)≥∑j=1n(∑i:vj∈eixi)H(Xvj∣X<j)≥∑j=1nH(Xvj∣X<j)=H(XV).

第二步用到了离散条件熵非负。另一方面,Xei 的支持集包含在 Ri 中,故 H(Xei)≤log⁡Ni。合并便有 log⁡|J|≤∑ixilog⁡Ni,取指数即得 AGM 界。边缘分布既不需要均匀,也不需要互相独立;均匀性只用于最初选取完整答案。

一般递归的成本为何不会乘出巨大中间表 ​

固定一次调用,记各非空投影大小为

bi=|πU∩ei(Ri[s])|,B=∏i≤kbiyi.

零列真关系的大小为一。所有 bi≥1,所以 B≥1;空切片检测的成本稍后另计。左递归的投影不比这里的大,故其预算 BL≤B,而 AGM 给出 |L|≤BL。

固定 w,令 ai(w)=|Ai|。若 α=yk<1,两种扩展的较小预算满足

(1)t(w)=min{p(w),q}≤p(w)1−αqα=qα∏i<kai(w)yi.

若 α≥1,扫描成本预算为 q;由于非空切片大小都至少一,同样有 q≤qα∏i<kai(w)yi。

现在不能直接将每个前缀的最坏成本乘以 |L|。需要把式 (1) 对 w 求和,并利用切片互不相交。所用的离散不等式是:若 zi≥0、∑izi≥1,则

(2)∑t∏ifi(t)zi≤∏i(∑tfi(t))zi(fi(t)≥0).

证明如下。零权重略去;若某个正权重因子的总和为零,左侧也为零。否则将每个 fi 除以自身总和,得到 0≤pi(t)≤1。令 c=∑izi、λi=zi/c,则 zi≥λi,从而

∑t∏ipi(t)zi≤∑t∏ipi(t)λi≤∑t∑iλipi(t)=1.

第二步是加权算术—几何平均不等式,证明了式 (2)。

按全局次序把 W 写为 w1,…,wd,从最后一个坐标开始消去求和。含有该坐标的因子具有总权重至少一,因为锚不含 W;不含该坐标的因子可提出求和号。对其余因子使用式 (2),切片大小的和至多是把该坐标重新加入投影后的大小。不同坐标值对应不相交切片;只对 L 允许的值求和可能漏掉一些切片,因此用的是“至多”。依次消去全部 W 坐标,得到

(3)∑w∈Lt(w)≤qα∑w∈L∏i<kai(w)yi≤∏i≤kbiyi=B.

没有剩余坐标时,式 (3) 就是单次扩展界。若某前缀的切片为空,直接拒绝它,不把检查开销记成“零时间”。

为把递归调度也写进账本,设 h(u) 为当前计划子树节点数。可按树归纳给出一个保守界:非空调用的时间至多为 Cmnh(u)B,其中 C 为统一常数。叶子扫描最小投影,其大小不超过 B,每个元组最多检查 m 张表、每次至多处理 n 个属性。内部节点的左递归由 BL≤B 支付;对所有右递归,归纳成本中的预算之和由式 (3) 支付。所有计数、空切片拒绝、分支决定和最终过滤的额外开销不超过 O(mn)(|L|+∑wt(w)+1)=O(mnB)。将左右子树系数相加再加当前节点,正好由 h(u) 控制。

根的非空输入给出 B=∏iNixi、H=h(root)≤mn。因此这份逐项账本证明了

(4)O(mnH∏iNixi+n2∑iNi+m2n),H≤mn.

对固定查询,m,n,H 都是常数;选择最优覆盖后就是 O(∑iNi+U)。式 (4) 故意保留一个较松的查询因子,以完整支付递归管理和空切片检查。原文更紧的 O(mnU+n2∑iNi+m2n) 作为其一般算法定理引用,[2, Theorem 3.2;4, Theorem 5.1] 并不冒称由这份较松账本已经证明同样的查询因子。求覆盖的线性规划成本另计;输入覆盖和预建索引都不是免费的隐藏步骤。

运行时间实际包含什么 ​

三角形算法读取、分组并建立哈希表索引,预处理的期望时间与空间都是 O(r+s+t)。假设属性值及固定长度元组可用常数个机器字表示,哈希与相等比较为常数成本,并维持适当负载因子,每个候选的成员检查具有期望 O(1) 成本。因此选择最佳证书后的总期望时间为

O(r+s+t+U).

答案可以流式输出,额外工作空间为 O(r+s+t);若保存全部答案,还须加上输出空间。长字符串的读写与比较、外存 I/O,以及比较树索引带来的对数因子,都不在这个单位成本哈希模型中。

固定查询的结构常数不能在查询也增长时隐去。NPRR 原文 Theorem 3.2 给出的一般界为 O(mnU+n2∑iNi+m2n),其中 m 是关系数、n 是属性数。这是枚举保证,与合取查询的联合成员判定 NP 完全、固定查询成员判定的数据复杂度结论回答不同的问题。

参考资料
  • [1] Albert Atserias、Martin Grohe、Dániel Marx,Size Bounds and Query Plans for Relational Joins,arXiv 上传版本,§3 Lemmas 2–4(PDF pp. 6–8)给出分数覆盖界;§4.1 Theorem 10(PDF pp. 11–12)给出指定关系大小时相差至多查询相关因子的紧性。

  • [2] Hung Q. Ngo、Ely Porat、Christopher Ré、Atri Rudra,Worst-case Optimal Join Algorithms,PODS 2012,§3.1 Example 2:三角形的重轻分解;§3.2 Theorem 3.2、Remark 3.3:一般运行时间与预处理假设。

  • [3] Hung Q. Ngo,Worst-case Optimal Join Algorithms 讲义,PDF pp. 3、16、24–25、40:最坏情形最优的含义、三角形界与熵证明。在线版本访问于 2026-10-03,文件未注明授课日期。

  • [4] Hung Q. Ngo、Ely Porat、Christopher Ré、Atri Rudra,Worst-case Optimal Join Algorithms,完整版本,§5.3,Algorithms 2–4、Procedure 5、Lemma 5.6(PDF pp. 17–22):计划树、索引、锚关系递归与切片求和;§6,Lemmas 6.1–6.2:至多一个非零坐标的实例族。正文四属性算例把该族的实际执行逐步展开。

关系图谱13 个相邻概念 · 2 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
类型化关系