AI 驱动查询计划生成:当机器学习接管优化器的代价估算

发布时间:2026/6/30 15:03:59

AI 驱动查询计划生成:当机器学习接管优化器的代价估算 AI 驱动查询计划生成当机器学习接管优化器的代价估算一、代价模型的尽头传统优化器的估算天花板数据库查询优化器的核心任务是从等价 SQL 的海量执行计划中选出代价最低的那一个。传统优化器基于统计信息和代价模型做这件事。但统计信息有采样偏差代价模型有独立性假设这些结构性缺陷在上一篇文章中已经分析过。问题在于随着数据规模和查询复杂度的增长这些缺陷被指数级放大。一个涉及 10 张表的 Join其排列组合有 10! 3,628,800 种。优化器不可能枚举所有可能只能依赖启发式规则剪枝。而启发式规则本身就是经验主义的产物——它在大多数场景下有效但在边界场景下可能严重偏离最优解。AI 驱动的查询计划生成本质上是用机器学习模型替代或增强传统代价模型中的关键估算环节。不是要推翻优化器的框架而是在其决策节点上注入更准确的预测能力。二、Learned Query Optimization从 LSTM 到 Transformer 的进化路径AI 查询优化的技术路线可以归纳为三类Learned Cost Model、Learned Join Ordering、End-to-End Plan Generation。flowchart TD A[AI 查询优化技术路线] -- B[Learned Cost Modelbr/学习型代价模型] A -- C[Learned Join Orderingbr/学习型 Join 排序] A -- D[End-to-End Plan Generationbr/端到端计划生成] B -- B1[用 ML 模型替代br/传统代价估算函数] B -- B2[输入计划特征向量] B -- B3[输出预测执行代价] C -- C1[用 RL/DRL 模型br/学习最优 Join 顺序] C -- C2[状态当前 Join 树] C -- C3[动作选择下一个 Join 表] D -- D1[用 Seq2Seq 模型br/直接生成完整执行计划] D -- D2[输入SQL 编码序列] D -- D3[输出算子序列]Learned Cost Model是最务实的路线。它不改变优化器的搜索框架只替换代价估算函数。具体做法是从历史查询的执行日志中提取特征表行数、索引基数、谓词选择率、Join 列的 NDV 等训练一个回归模型来预测实际执行时间。Neo、Microsoft 的 QPP 等项目采用了这条路线。Learned Join Ordering用强化学习来学习最优 Join 顺序。状态空间是当前的 Join 树结构动作空间是选择哪张表做下一个 Join奖励是执行时间的倒数。DeepMind 的 Bao 和 MIT 的 Neo 都在这个方向上有探索。核心挑战是训练数据需要大量最优 Join 顺序的标注而获取标注本身就需要穷举执行计划代价极高。End-to-End Plan Generation最激进直接用 Seq2Seq 模型将 SQL 文本映射为执行计划。这条路线的泛化能力最差因为 SQL 的语义空间和执行计划的空间都是开放集模型很难覆盖未见过的查询模式。三、生产级实现Learned Cost Model 的特征工程与模型选型在三种路线中Learned Cost Model 最适合生产落地。以下是一个基于 XGBoost 的代价预测模型实现import xgboost as xgb import numpy as np from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_percentage_error class LearnedCostModel: 学习型代价模型替代传统优化器的代价估算函数 def __init__(self, model_pathNone): self.model xgb.XGBRegressor( n_estimators500, max_depth8, learning_rate0.05, subsample0.8, colsample_bytree0.8, # 回归任务使用绝对误差对异常值更鲁棒 objectivereg:absoluteerror, eval_metricmape ) self.feature_names [ table_rows, # 表行数 index_cardinality, # 索引基数 predicate_selectivity,# 谓词选择率 join_ndv, # Join 列的 NDV data_size_mb, # 数据量MB index_height, # 索引树高度 range_scan_flag, # 是否范围扫描 join_type, # Join 类型编码 subquery_depth, # 子查询嵌套深度 ] if model_path: self.model.load_model(model_path) def extract_plan_features(self, plan_node): 从执行计划节点提取特征向量 关键设计特征必须包含数据分布信息 而非仅结构信息否则模型无法区分 数据倾斜场景下的代价差异 features [ plan_node.get(table_rows, 0), plan_node.get(index_cardinality, 0), plan_node.get(predicate_selectivity, 0.0), plan_node.get(join_ndv, 0), plan_node.get(data_size_mb, 0.0), plan_node.get(index_height, 0), 1 if plan_node.get(access_type) range else 0, self._encode_join_type(plan_node.get(join_type, none)), plan_node.get(subquery_depth, 0), ] return np.array(features, dtypenp.float32) def train(self, plan_features, actual_costs): 训练代价预测模型 actual_costs 使用归一化后的执行时间ms 避免不同硬件环境下的绝对值差异 X_train, X_val, y_train, y_val train_test_split( plan_features, actual_costs, test_size0.2, random_state42 ) self.model.fit( X_train, y_train, eval_set[(X_val, y_val)], verboseFalse ) y_pred self.model.predict(X_val) mape mean_absolute_percentage_error(y_val, y_pred) print(f验证集 MAPE: {mape:.4f}) return mape def predict_cost(self, plan_node): 预测执行计划的代价 返回值为预测的归一化执行时间 可直接替换优化器中的 cost() 函数返回值 features self.extract_plan_features(plan_node) features features.reshape(1, -1) return float(self.model.predict(features)[0]) staticmethod def _encode_join_type(join_type): Join 类型编码将离散值映射为数值 mapping { none: 0, inner: 1, left: 2, right: 3, full: 4, cross: 5 } return mapping.get(join_type, 0)模型选型上XGBoost 优于深度学习模型的原因有三训练数据量通常在万级到十万级深度学习容易过拟合特征维度低通常 10-30 维树模型的表达能力足够可解释性强能通过特征重要性分析定位代价估算的薄弱环节。四、AI 优化器的现实困境冷启动、分布漂移与可解释性AI 优化器不是银弹它有三个结构性难题尚未解决。冷启动问题。新上线的业务没有历史执行数据模型无法训练。解决方案是用传统代价模型的输出作为预训练标签在积累真实执行数据后再做微调。但这意味着初期 AI 优化器的预测精度不会优于传统模型甚至可能更差。数据分布漂移。业务数据分布会随时间变化模型在训练数据上的表现不能代表未来的表现。必须建立持续学习机制定期用最新执行数据重训练模型同时监控预测误差的变化趋势。当 MAPE 超过阈值时触发告警并自动重训练。可解释性缺失。当 AI 优化器选错了执行计划DBA 需要知道为什么选错。XGBoost 可以输出特征重要性但无法解释单次决策的逻辑。这在生产环境中是硬伤——出了事故你不能告诉老板模型就是这么预测的。更深层的问题是AI 优化器引入了新的故障模式。传统优化器的行为是确定性的同样的 SQL 在同样的统计信息下一定产生同样的执行计划。但 AI 优化器的预测结果可能因模型版本不同而变化这给故障复现带来了额外复杂度。五、总结AI 驱动查询计划生成的核心价值在于弥补传统代价模型在数据分布估算上的结构性缺陷。但它不是替代品而是增强工具。生产落地的正确姿势是AI 模型作为代价估算的第二意见与传统模型做交叉验证当两者偏差超过阈值时回退到传统模型。落地路线建议从 Learned Cost Model 切入积累至少 1 万条带真实执行时间的查询样本特征工程优先纳入数据分布信息NDV、直方图分位数而非仅结构信息部署双轨验证机制AI 预测代价与传统代价同时计算偏差超 30% 时以传统代价为准建立模型监控看板追踪 MAPE 趋势和执行计划漂移率每周用增量数据重训练模型保留最近 3 个模型版本用于 A/B 对比

相关新闻