课程视频
截至 2026 年 10 月 2 日,所给 B 站收藏夹收录到第 14 讲,官网 Schedule 未提供本讲视频链接。本页依据指定论文整理。
用模型表达传统摘要丢失的关系
第 15 讲的笔记依据官网指定阅读整理。传统基数估计用直方图、高频值和 NDV 压缩数据,再采用均匀性、独立性等假设。学习型估计希望用模型保存更复杂的列间或表间关系。
主要阅读 Learned Cardinality Estimation: An In-depth Study。论文比较支持 Join 的多类方法,并研究复杂数据上的误差来源。它的主要范围是内部 Join 的选择、投影、连接查询,阅读结论时应保留这一边界。
先用一个扩展示例理解目标:country = 'China' AND currency = 'CNY' 的交集概率依赖国家与币种的相关性。两个单列概率相乘容易低估;联合模型则尝试直接表示二者同时成立的概率。
Query-Driven:从查询及其答案学习
查询驱动方法使用带标签的训练查询,标签通常是该查询的真实基数。输入特征可以包括表集合、Join 条件、过滤列、运算符、常量,以及样本命中信息。
1 | 训练:查询特征 → 真实基数 |
例如训练集包含订单日期、状态与客户地区的不同组合,模型学习这些条件如何影响行数。MSCN 一类方法将不同数量的表、谓词和 Join 特征作为集合编码,适应查询结构的变化。
标签获取成本很重要。执行大量 COUNT(*) 查询可以获得真实答案,但复杂 Join 标签可能十分昂贵。训练查询还需要覆盖有意义的参数范围;只学习常见模板,面对未出现的列组合和 Join 子图时仍可能出现大误差。
Data-Driven:先学习数据分布
数据驱动方法直接从表或多表采样学习分布,再把查询转换成概率计算。单表情况下,可用下面的教学表达理解:
1 | 估计行数 ≈ 表行数 × P(各过滤条件同时成立) |
自回归模型按某个列顺序分解联合概率:
1 | P(A, B, C) = P(A) × P(B | A) × P(C | A, B) |
条件概率可以表达 A、B、C 的依赖。范围条件需要累加或采样估计多种取值的概率,推理次数、采样方差和列顺序都会影响结果。NeuroCard 一类方法使用这类分布表示;DeepDB 使用 Sum-Product Network(和积网络)等结构表达联合关系。
多表估计比单表更复杂。训练分布若基于 Join 结果,一个基本表行可能因一对多连接出现多次。模型预测的概率要经过适当的归一化和 fanout(匹配扩张倍数)处理,才能回到目标查询的行数。直接拿联合概率乘某张基本表行数,通常无法得到正确结果。
用同一组数据比较独立估计与联合概率
构造一张一万行的教学表:中国用户有 6000 行,其中 5900 行使用 CNY;其他国家的 4000 行中另有 100 行使用 CNY。于是 P(country=China)=0.6,P(currency=CNY)=0.6,联合条件的真实概率为 0.59。
独立性估计得到 10000 × 0.6 × 0.6 = 3600 行,实际为 5900 行。采用条件概率则有:
1 | P(China, CNY) = P(China) × P(CNY | China) |
自回归模型的分解形式能表示这项相关性,预测是否准确取决于学到的条件分布。查询驱动模型则可以从带真实基数标签的这些谓词组合学习同一关系。两者拥有不同训练输入,但都需要覆盖相关区域。
如果工作负载忽然查询此前没有出现的新币种,查询驱动编码要处理未知常量;数据驱动模型也需要在训练数据或更新流程中认识这个值。模型类别本身不提供自动正确的外推保证,应检查具体方法的编码、平滑、更新与回退设计。
Join 样本为什么需要处理 fanout
设客户 1 有十笔订单,客户 2 有一笔订单。对客户与订单的完整 Join 均匀采样,客户 1 占据十行中的贡献,客户 2 只贡献一行。样本中的客户分布已经被订单数量加权。
如果目标查询只统计客户数量,直接把 Join 样本的比例乘客户总数,可能把订单多的客户看得过重。多表模型需要区分目标 Join 结果、基本表事件和匹配扩张倍数,并采用论文定义的归一化方法。查询只使用完整训练 Join 的一部分表时,还可能需要处理未参与表对样本分布的影响。
因此阅读 NeuroCard、DeepDB 等方法时,应先写出它们学习的是哪一个关系分布,以及估计目标从该分布怎样得到。模型网络结构只能解释表示能力,概率到目标基数的转换同样决定正确性。
两种训练来源怎样取舍
| 维度 | 查询驱动 | 数据驱动 |
|---|---|---|
| 主要训练材料 | 查询与基数标签 | 表数据或 Join 样本 |
| 学习对象 | 查询特征到结果规模的映射 | 数据中的联合分布 |
| 明显成本 | 标签执行与查询生成 | 数据扫描、采样及分布训练 |
| 变化风险 | 新模板、新谓词组合 | 数据更新、未覆盖的连接结构 |
这是理解方法来源的分类,实际方案可以组合两种信号。研究一个具体模型时,还要看支持的 Join 类型、过滤形式、未知类别与空值的编码。
为什么更复杂的数据会暴露问题
主阅读论文把实验扩展到完整 IMDB 和 TPC-DS 等更复杂场景,并分析训练分布、连接处理和模型表达能力。表数、列数与相关关系增加以后,先前在较小数据集上的准确性不一定保持。
一个极低选择率查询只覆盖概率分布的很小区域。训练或推理采样没有覆盖该区域时,相对误差容易很大;某个热点键的 fanout 很高时,多表归一化误差也会被放大。这些情况需要从模型机制解释,而不能只给出“黑盒预测不准”。
Are We Ready For Learned Cardinality Estimation?进一步讨论部署相关的要求。本文把更新和回退作为学习时应检查的工程问题,具体实现应以各方法论文为准。
预测成本与预测基数的不同接口
学习型基数模型预测“会产生多少行”,物理模型仍需据此估计工作量。学习型代价模型可以直接预测算子或计划的成本,也可以使用传统模型输出作为特征,再学习误差修正。
输入相同基数的两个计划,可能因为索引回表、缓存、并行度和内存溢写而运行时间不同。因此一个准确的 CE 模型不能独自解决全部成本问题。Rethinking Learned Cost Models讨论如何利用已有成本信号,而非丢掉已有模型积累。
把一次推理成本乘回整个搜索
假定一次优化需要估计两万个候选,传统摘要计算每次耗时 5 微秒,总计约 100 毫秒;一个模型每次推理 0.5 毫秒,逐项调用就需要约 10 秒。这些数字用于演示规模效应,与具体模型的实测性能无关。
批处理可以摊薄部分推理开销,但 Top-Down 搜索不一定事先知道全部候选,部分输入还要等待前面的任务完成。缓存能复用相同逻辑表达式的估计,不过缓存键需要包含参数、数据或模型版本。只在计划敏感的少量候选上调用复杂模型,则需要选择这些候选的策略。
最终应比较总时间:编译增加了多少,执行减少了多少。短查询若只运行一次,模型获得的执行收益可能不足以支付额外编译;同一模板频繁执行时,缓存与复用又会改变取舍。训练与维护预算是另一条成本线,需要单独记录。
在优化循环中评估模型
优化器可能为一次查询估计大量候选表达式。若传统估计一次花费很小,而模型每次推理都需要毫秒级开销,总编译时间就可能显著增加。推理缓存、批处理或选择性调用的可行性,需要结合候选复用与任务依赖判断。
评价时应同时观察 Q-error 分布、最终计划质量、总查询延迟、模型内存、训练与更新成本。均值改善可能掩盖尾部大误差,计划选择阈值附近的误差也可能更加重要。
部署层面还应确认数据版本与模型版本相符,遇到不支持的谓词或未知值时有定义清楚的回退路径。这里没有单一通用阈值;应由实际工作负载和基线测量决定。
读完本讲,可以选一个强相关列组合,分别推导独立性公式、查询驱动预测所需标签和数据驱动概率所需信息,再判断哪个成本最值得支付。
参考资料
Learned Cardinality Estimation: An In-depth Study (K. Kim et al., SIGMOD 2022) (Primary)
Learned Cardinality Estimation: A Design Space Exploration and A Comparative Evaluation (J. Sun et al., VLDB 2022) (Optional)
Are We Ready For Learned Cardinality Estimation? (X. Wang et al., VLDB 2021) (Optional)
Rethinking Learned Cost Models: Why Start from Scratch? (J. Yang et al., SIGMOD 2023) (Optional)
An End-to-End Learning-based Cost Estimator (J. Sun et al., VLDB 2019) (Optional)
