技术原理
核心机制
- 反馈基数估计
反馈基数估计首先需要为每个待预测算子动态匹配对应的预测模型,其匹配逻辑基于算子特征的唯一哈希编码,该编码综合了算子所涉及的表、属性及查询条件等信息。同时,另一个机制为利用算子级别的历史数据,训练并应用UMM (Unified Mixture Model) 和 KNN (K-Nearest Neighbors) 模型,建模查询条件与实际基数间的关系。
- 算子哈希值计算:
为准确匹配模型,系统会为每个查询算子生成一个独特的特征标识(哈希值)。该标识的核心在于捕捉算子查询条件的关键模式特征。一个查询算子由四个基本要素描述:
- 属性组(等价类): 表示具有相等关系的属性集合(例如,从a.id = b.id AND b.id = c.id的连接条件中可提取 {a.id, b.id, c.id} 为一组)。
- 比较操作符: 如查询条件中的=、>、<等。
- 条件值: 可以是具体数值(如 a.id = 5),也可以是另一个属性组(例如在a.id < b.id中)。
- 条件类型: 查询条件的类型,包括过滤型查询条件(如 a.id = 5)、连接型查询条件(如 a.id = b.id)等。
在计算给定算子的哈希值时,将首先提取以上四个要素,并分别计算四个要素的哈希值,再计算总哈希值,特别地,等价类的哈希值由其包含的所有属性的哈希值组合生成。
- UMM模型构建:
- n维查询条件空间的边界值,定义了模型覆盖的范围。
- M个采样得到的超方体,这些超方体位于上述n维查询条件空间内。
- 每个采样超方体对应的权重。
对于一个待预测的查询算子,UMM的基数估计过程如下:
- 根据该算子的查询条件,在n维查询条件空间中确定其对应的查询超方体。
- 计算该查询超方体与每一个采样超方体的重叠部分的n维测度(在二维情况下即面积,三维即体积,以此类推)。
- 将这些重叠部分的测度,分别乘以其对应采样超方体的权重。
- 将所有加权后的测度求和,该总和即为该查询算子的预测基数。
以图1中的二维情况 (n=2) 为例说明:
- 查询条件空间是一个二维平面,采样超方体即为平面上的矩形(即二维超方体),UMM模型假设在每个采样矩形覆盖的区域内,数据满足均匀分布。
- 对于待预测算子,其查询条件对应一个矩形区域(图中蓝色矩形所示)。
- 该查询矩形的预测基数,等于它与所有采样矩形重叠区域面积的加权和(权重为对应采样矩形的权重)。
而UMM模型的训练过程即为构建采样超方体和确定其权重的过程。具体而言,根据收集到的历史查询算子的查询条件信息,确定覆盖这些条件的初始超立方体集合(代表整个或部分查询空间),从这些初始超立方体中采样,得到M个采样超立方体(子区间),再利用梯度下降算法,训练优化这M个采样超立方体的权重参数。优化的目标是使模型对训练数据的基数预测误差最小。
- KNN模型构建:
K近邻模型(KNN)核心思路,是利用历史查询数据来建立查询条件的选择率特征与最终查询基数之间的映射关系。
假设关注的算子类型包含若干个(N个)查询条件。每个查询条件都有一个默认的估计选择率,这些选择率值可以组合成一个特征向量(通常记为 x)。这个算子对应的实际查询基数就是目标值(通常记为 y)。
KNN模型本身并不存储复杂的数学参数,它的核心“知识”来源于其内部保存的历史查询样本。具体来说,一个针对特定查询模式的KNN模型,最多会存储K个历史样本。每个样本都记录了过去一次同类查询的特征向量x(即当时各个查询条件的默认选择率估计值)和其对应的真实查询基数y。
在进行预测时,查询优化器会首先根据当前待估计查询算子的特征(通常通过哈希匹配模式)找到对应的KNN模型。然后,优化器会提取当前查询中各个条件的默认选择率估计值,形成当前的特征向量x。模型接着会在其存储的K个历史样本中,找出与当前特征向量x最相似的K个邻居样本。最终的查询基数预测值(ŷ)是通过对这K个邻居样本的真实基数(y)进行加权平均得到的。这个加权平均的权重取决于每个邻居样本的特征向量(x)与当前查询特征向量(x)的相似度:两个向量越相似(距离越近),其对应的真实基数在预测中所占的权重就越大。模型使用一种特定的相似度度量函数(基于向量间的欧几里得距离)来计算这个权重。
如图2的例子所示,在查询条件为2的场景中,每个特征向量可以表示为二维平面上的一个点,右侧图中黑色的点即为KNN模型中的训练数据,在预测过程中,根据待预测的查询条件的选择率,可以得到其特征向量和图中对应的位置(图中的红点),再根据KNN算法,图中红色的圈表示以红点为中心、包含K个最近邻历史样本的搜索范围(即邻域)。这个圈的大小取决于距离红点第K近的历史样本的距离,通过计算当前特征向量(红点)与圈内每个历史样本特征向量(黑点)的相似度(基于欧几里得距离),并根据相似度分配权重,最终通过加权平均预测查询基数(ŷ)。
- 算子哈希值计算:
- 代价估计参数调整
- I/O 成本参数(seq_page_cost / random_page_cost):
基于实际测量的平均I/O时间(总I/O时间/读取页面数),并依据默认比例关系(seq_page_cost : random_page_cost = 1:4)直接计算:seq_page_cost = 平均I/O时间 / 2,random_page_cost = 平均I/O时间 * 2。
- CPU成本参数 (cpu_tuple_cost、cpu_index_tuple_cost、cpu_operator_cost):
- cpu_tuple_cost (主回归目标): 使用线性回归模型计算。该模型针对顺序扫描 (SeqScan) 算子建立:执行时间 = 处理元组数 * (cpu_tuple_cost + 表达式单位CPU操作数 * cpu_operator_cost)。
- cpu_index_tuple_cost: 鉴于索引扫描 (IndexScan) 的性能受顺序性影响显著且分析复杂,该参数不直接回归,而是基于回归得到的 cpu_tuple_cost和默认比例设定:cpu_index_tuple_cost = cpu_tuple_cost / 2。
- cpu_operator_cost:同样不直接回归。考虑到提供的单位CPU操作数可能与实际开销存在较大偏差,且多元回归易受数据质量(如样本同质化)影响,采用默认比例设定:cpu_operator_cost = cpu_tuple_cost / 4。此设定将SeqScan模型简化为无常数项的一元回归:执行时间 = 元组数 * cpu_tuple_cost * (1 + 表达式单位 CPU 操作数 / 4)。
- 参数可靠性检验:
- 训练数据通过滑动窗口管理(默认长度 cost_update_window_size = 5)。
- 每次窗口数据完全更新后,使用前次训练的参数计算新窗口数据的拟合优度:计算决定系数R² = 1 - (Σ(估计误差²) / 窗口长度)。
- 仅当R² > 0.95 时,才认为本次回归结果可靠并采纳新参数,否则继续收集数据等待后续训练。
- I/O 成本参数(seq_page_cost / random_page_cost):
性能指标
在开启此功能后,反馈基数估计模型训练收敛的情况下,在JOB(Join-Order-Benchmark)测试集能够产生端到端的平均1.3倍的查询速度提升。
接口介绍
- 核心系统函数:
函数名
函数说明
gs_acm_analyze_workload_manual()
根据当前已收集的算子信息,手动启动模型训练与更新。
gs_stat_get_acm_feedback_operator_info()
查看目前全局内存中已收集到的所有算子信息。
gs_costmodel_calibration_manual()
手动开始收集代价信息并且矫正代价模型参数一次。
具体描述及其他相关系统函数请参见《参考》中“SQL参考 > 函数和操作符 > AI特性函数”章节。
- 核心GUC参数:
参数名
级别
默认值
描述
enable_adaptive_cost
SIGHUP
on
总功能的开关,控制算子信息收集与反馈基数估计流程的启停,并同步控制后端模型维护线程的启停。
enable_feedback_cardest
USRSET
on
单独控制反馈估计功能的开关,当enable_adaptive_cost关闭但enable_feedback_cardest为开启时算子信息会被收集,且反馈基数估计接口仍会被调用,但后端自动模型维护的线程并不会被拉起,可以通过gs_acm_analyze_workload_manual()函数手动训练模型。
adaptive_cardest_strategy
USRSET
auto
设置选择基数估计模型偏好,可选择类型:
- 'auto':根据过去预测误差选择模型。
- 'use_statistics':优先使用统计信息做基数估计。
- 'use_feedback':优先使用反馈模型做基数估计。
adaptive_cost_min_time
USRSET
1000ms
参数用于设置算子收集的SQL时间阈值,只有执行时间大于该值的语句的执行算子才会被收集。
cost_update_window_size
USRSET
5
调整收集用于自适应代价模型参数回归的数据的滑动窗口大小,范围为[1,20]。
adaptive_costest_strategy
USRSET
L0
设置代价评估使用新/旧代价的策略,当前分为两个等级:
- 'L0':如果计划树代价估计使用的所有基数都是可信任的(基表SeqScan/基数来自反馈基数/支持反馈基数但尚未训练/估计误差<1.1的默认基数),才会计算和使用新代价做计划选择。
- 'L1':任何时候都使用新的代价模型计算。
具体描述与其他相关GUC参数请参见《参考》中“数据库运行参数说明 > GUC参数说明 > AI特性”章节。

