news 2026/9/20 2:46:20

CardBench 训练查询图(Training Query Graphs)完全指南:从 SQL 查询到零样本基数估计的训练数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CardBench 训练查询图(Training Query Graphs)完全指南:从 SQL 查询到零样本基数估计的训练数据
  • 人工智能
  • 深度学习
  • NLP
  • 计算机视觉
  • 强化学习

【免费下载链接】google-research

Google Research

项目地址:https://gitcode.com/gh_mirrors/go/google-research
点击查看免费下载

导读

本指南系统讲解 CardBench(关系数据库学习型基数估计基准)的核心数据资产——训练查询图(Training Query Graphs)。你将理解三个训练数据集(单表、二表连接、多表连接)的构成与规模、查询图的节点/边特征模式(Schema)、以及如何使用 sparse-deferred 库读取.npz格式的训练数据并提取基数、执行时间、SQL 等标注信息,为训练或评估基数估计模型(包括零样本场景)打下数据基础。文中所有示例均可直接运行,并有仓库源码佐证其底层实现。

什么是 CardBench 训练查询图

CardBench 是 Google Research 发布的用于关系数据库学习型基数估计(Learned Cardinality Estimation)的基准,仓库中同时包含两部分内容:训练数据集(位于training_datasets目录)与生成训练数据集的完整代码。其中,训练查询图正是 TrainingQueryGraphs.md 所详细描述的核心交付物。

每个训练实例都是一条 SQL 查询的"带注释图"(annotated graph):原始 SQL 字符串被翻译为关系代数算子、查询计划,最终转换为图结构;同时,通过真实数据库(Google BigQuery)执行该查询得到的**实际基数(cardinality)**被作为上下文信息写入图中。因此,每条训练样本同时包含:

  • 查询本身的执行语义(以节点和边编码);
  • 查询涉及的数据库对象统计信息(表行数、列分位数、空值比例等);
  • 查询的真实执行结果(cardinality)与执行时间(exec_time)等顶层标签。

CardBench 的训练数据集按查询复杂度分为三档,三者的差异在于查询包含的操作类型:

数据集查询形态谓词规模
Single Table(单表)对单张表应用过滤每查询 1–4 个过滤谓词
Binary Join(二表连接)连接两张表每张表 1–3 个过滤谓词
Multi Join(多表连接)1–7 个连接每张表 0–2 个过滤谓词

下面分别是官方文档给出的单表与二表连接查询示例:

-- Single Table 示例 SELECT count(*) FROM tpch_10G.nation as nation WHERE nation.n_nationkey <= 6 AND nation.n_comment IS NULL AND nation.n_regionkey >= 1;
-- Binary Join 示例 SELECT count(*) FROM tpch_10G.region as region JOIN tpch_10G.nation as nation ON region.r_regionkey = nation.n_regionkey WHERE nation.n_comment IS NOT NULL AND nation.n_nationkey != 5;

这些查询的真实基数是在 Google BigQuery 上执行后获得并作为图上下文(context)写入的,SQL 字符串本身也包含在图上下文之中。

训练数据的下载与文件命名规范

训练数据集以.npz文件形式提供,命名规范为:

database_name_<single_table|binary_join|multi_join>.npz

例如consumer_single_table.npztpch_10G_binary_join.npzaccidents_multi_join.npz。下载方法与全部制品链接(数据集 CSV、建表 SQL、复制脚本、元数据 JSON、查询图文件)请参考 DowloadArtifacts.md。文档特别说明:数据库名称中的~标记表示该数据库已被降采样(down sampled)

训练数据集总览

下表列出了 20 个数据库的规模信息:每个数据库包含的表数量、以及各数据集(单表/二表连接/多表连接)的查询图数量。这些查询图由不同复杂度的查询生成,是训练与评估(含零样本)基数估计模型的基础:

数据集名称表数单表查询数二表连接查询数多表连接查询数
accidents39125845429242
airline1965681309610467
consumer35961557111857
employee6126751041711041
movielens13144881575717067
sample_cms_synthetic_patient_data_omop249574653610038
sample_covid19_weathersource_com493661018616075
sample_crypto_bitcoin_cash2143151240417114
sample_ethereum_blockchain7197561742419962
sample_geo_openstreetmap16163461500010979
sample_github_repos95268451310564
sample_human_variant_annotation26138621408512162
sample_idc_v10198609646412081
sample_open_targets_genetics139734905810025
sample_samples888931136910832
sample_stackoverflow14143051277311399
sample_usfs_fia11138221178710980
sample_uspto_oce_claims125925612311968
sample_wikipedia256659737510739
tpch_10G8117271318116318

观察可见,多数数据库的查询图总量在数万级别;accidents的多表连接查询数高达 29242,是全表中最多的。用户可按需组合这些文件构建自己的训练/验证/测试划分,例如在零样本实验中用其中 19 个数据库训练、留出 1 个数据库做测试(仓库中 graph_transformer/README.md 提供了这种划分的完整命令)。

查询图结构:节点类型、特征与边的 Schema

CardBench 查询图是一种异构图(heterogeneous graph)。下图为查询图的结构示意:左侧列出了各节点类型及其特征与数据类型,右侧则可视化了一个具体示例查询对应的图:

图中的核心观察:

  • 节点类型包括tables(表)、attributes(列/属性)、predicates(谓词)、ops(算子,如 scan/join)、correlations(列间相关关系),外加一个表示全局上下文的特殊节点g(在官方示例输出中以'g'出现)。
  • 边类型则刻画了这些节点之间的语义关系,如table_to_attr(表到列)、attr_to_pred(列到谓词)、pred_to_pred(谓词组合,如 AND/OR)、attr_to_op(列到算子)、op_to_op(算子之间)、pred_to_op(谓词到算子)、attr_to_corr/corr_to_pred(列到相关关系、相关关系到谓词)。

从仓库源码 constants.py 可以确认图结构的完整定义:NODE_TYPES包含pseudo_nodeattributesopspredicatescorrelationstables六类,EDGE_TYPES则定义了 9 种边(含pseudo_edge)。各节点的具体特征如下:

节点类型特征(features)说明
g(全局上下文)cardinalityexec_timequery_idquery(SQL 字符串)等一条查询的顶层信息与监督标签
tablesrows(行数)、name(表名)表级统计
attributesnamedata_typenull_frac(空值比例)、num_unique(唯一值数)、percentiles_100_numeric/percentiles_100_string(101 位分位数)、min/max_numericmin/max_string列级统计
predicatespredicate_operator(算子编码)、estimated_selectivity(估计选择率)、offset(长度 6 的偏移向量)、constantencoded_constant谓词信息
opsoperator(如scanjoin执行算子
correlationstypecorrelation(Pearson 相关系数)、validity列间相关性

特征填充规则与占位值

文档在 Notes 中明确了两条重要规则:

  1. 按属性类型选择性填充特征percentiles_str(字符串分位数)只对STRING类型属性填充,percentiles_num(数值分位数)只对数值类型属性填充。这点在源码 convert_query_plan_to_graph.py 中得到了印证:只有INT64NUMERICBIGNUMERICFLOAT64DECIMALBIGDECIMAL类型才会写入min_numeric/max_numeric,否则填-1percentiles_100若缺失则填充 101 个-1.0
  2. 空特征统一填充-1:任何未填充的特征占位值均为-1

从 constants.py 还可以看到,训练图 Transformer 在预处理时会移除部分非数值特征(如attributes.namemin/max_stringpercentiles_100_stringpredicates.constant等),并把data_typeoperatorpredicate_operatorvalidity等作为分类特征做 one-hot 化(CATEGORICAL_FEATURE_UNIQUE_DICT),最终拼成维度为NODE_FEATURE_DIM = 150的节点特征向量,用于 graph_transformer 模型输入。

此外,各数据库更完整的统计信息可在 DowloadArtifacts.md 中获取,查询图中已经内嵌了一部分数据集统计信息。

如何读取训练数据(sparse-deferred 实战)

训练数据使用 Sparse Deferred 正是查询图生成管线中负责把图转换为 sparse-deferredGraphStruct对象并最终写入.npz文件的模块。

环境要求

运行下述读取代码需要:

  • Python >= 3.10
  • sparse-deferred
  • numpy

三者均可通过 pip 安装。

加载训练数据集

训练数据集以分片(sharded)方式存储(即拆分为多个文件),可用 glob 找到某个数据集的所有分片。以下代码加载consumer_single_table数据集并打印训练实例数量:

from sparse_deferred.structs import graph_struct GraphStruct = graph_struct.GraphStruct InMemoryDB = graph_struct.InMemoryDB # 训练数据集按分片存储,使用 glob 查找某数据集的所有分片 filename = "single_table/consumer_single_table.npz" db = InMemoryDB.from_file(filename) # 打印训练实例数量 print("Number of training instances:", db.size)

输出:

Number of training instances: 5571

该数字与上表consumer单表查询数 5961 存在差异,原因在于查询图生成过程中会过滤掉重复查询零基数查询(见下文"源码佐证")。

查看 Schema 与节点类型

# 打印训练实例的 schema print("Schema:", db.schema)

输出:

Schema: {'table_to_attr': ('tables', 'attributes'), 'attr_to_pred': ('attributes', 'predicates'), 'pred_to_pred': ('predicates', 'predicates'), 'attr_to_op': ('attributes', 'ops'), 'op_to_op': ('ops', 'ops'), 'pred_to_op': ('predicates', 'ops'), 'attr_to_corr': ('attributes', 'correlations'), 'corr_to_pred': ('correlations', 'predicates')}
# 打印节点类型 print("Node types:", first_training_example.nodes.keys()) # 打印表节点的特征 print("Table node features:", db.get_item(0).nodes["tables"].keys())

输出:

Node types: dict_keys(['g', 'tables', 'attributes', 'predicates', 'ops', 'correlations']) Table node features: dict_keys(['rows', 'name'])
# 打印边类型 print("Edge types:", first_training_example.edges.keys())

访问表节点信息

# 打印第一个表节点的行数和表名 print( "First table number of rows:", db.get_item(0).nodes["tables"]["rows"][0] ) print("First table name:", db.get_item(0).nodes["tables"]["name"][0])

输出:

First table number of rows: 340872 First table name: b'bq-cost-models-exp.consumer.HOUSEHOLDS'

访问图级特征(基数、执行时间、SQL)

cardinalityexec_timequery_idquery等是图级(graph level)特征,即查询本身的监督标签:

# 打印查询基数、执行时间、query_id 与 SQL 字符串(均为图级特征) print( "Query cardinality:", first_training_example.nodes["g"]["cardinality"][0], ) print("Execution time:", first_training_example.nodes["g"]["exec_time"][0]) print("Query id:", first_training_example.nodes["g"]["query_id"][0]) print("Query:", first_training_example.nodes["g"]["query"][0])

输出:

Query cardinality: 824130 Execution time: 2390.0 Query id: 14211 Query: b'SELECT count(*) as rwcnt FROM `bq-cost-models-exp.consumer.HOUSEHOLDS` as HOUSEHOLDS JOIN `bq-cost-models-exp.consumer.HOUSEHOLD_MEMBERS` as HOUSEHOLD_MEMBERS ON HOUSEHOLDS.HOUSEHOLD_ID = HOUSEHOLD_MEMBERS.HOUSEHOLD_ID;\n'

打印完整训练实例

# 获取并打印第一个训练实例 first_training_example = db.get_item(0) print("First training example:", first_training_example)

输出为完整的GraphStruct序列化表示,包含全部节点特征(如attributes节点的null_fracnum_uniquepercentiles_100_numericpercentiles_100_string等)与 8 类边的邻接索引。例如上面这个 consumer 二表连接查询实例中:

  • ops节点为[b'join', b'scan', b'scan'](一个 join 算子加两个 scan 算子);
  • predicates节点为空(该查询没有过滤谓词,仅做连接);
  • correlations节点为空数组(未计算相关关系)。

一个值得注意的细节:该示例查询实际上是一条二表连接(HOUSEHOLDS JOIN HOUSEHOLD_MEMBERS),但它出现在单表数据集的加载演示中——官方文档选取此例是为了演示InMemoryDB的读取 API,读者在实际使用时应按数据集类型(single_table/binary_join/multi_join)选择对应文件。

源码佐证:查询图是如何生成的

了解查询图"从哪来",有助于正确解读图内容。根据 README.md 与generate_training_querygraphs_library目录,查询图的生成是 CardBench 代码管线的最后一步:

  1. 生成 SQL 查询(generate_queries_and_save_to_file.py,基于 DataManagementLab 的 zero-shot-cost-estimation 查询生成器改进);
  2. 执行查询收集真实基数(run_queries.py,将每条查询的 SQL 与 cardinality 存入QUERY_RUN_INFORMATION_TABLE);
  3. 生成带注释查询图(generate_training_querygraphs_and_save_to_file.py):SQL 字符串 → 关系代数算子(convert_sql_to_relational_operators.py)→ 查询计划(convert_relational_operators_to_query_plan.py)→ 图(convert_query_plan_to_graph.py),并注释数据集统计信息;
  4. 保存为 sparse-deferred 格式(create_sparse_deferred_graph_struct_object.py,InMemoryDB收集图对象后统一写入.npz文件)。

其中两条源码事实值得注意:

  • 去重与零基数过滤:在 generate_training_querygraphs_helpers.py 的find_unique_and_non_zero_cardinality_queries中,生成时会剔除cardinality == 0的查询,并基于"表集合 + 谓词(含常量/不含常量)"构造签名字符串来去除重复查询计划。这就是为什么最终.npz中的实例数通常少于原始生成的查询数。
  • 查询图校验:在 validate_query_plan_and_graph.py 中,生成后会做严格校验:每张图必须满足"join 节点数 = SQL 中 JOIN 数、scan 节点数 = 表数"等约束;每个 column 节点必须携带min_valmax_valpercentilespercentiles_100(长度必须为 101)、null_fracnum_unique等字段;相关关系节点的correlation值与validity状态(如validnanmissinginvalidtypesnone)必须相互匹配。

这些校验规则解释了读取数据时看到的各种占位值(如-1填充、-10/-20/-50等特殊相关系数取值),帮助读者判断某个特征"缺失"是语义上的正常占位还是异常。

下一步:将查询图用于基数估计模型

读取查询图后,最直接的用法是训练或评估基数估计模型。仓库提供了配套的图 Transformer 实现,位于 graph_transformer 目录,其工作流程为:

  1. 构建缩放策略:用 build_scaling_strategy.py 在所有训练数据集上计算全局统计(数值特征缩放参数),输出scaling_strategy.json
  2. 预处理:用 preprocess_dataset.py 将.npz查询图批量转换为 TF Dataset;
  3. 训练:用 train.py 支持三种模式:
    • 实例内模型(instance based):同一数据集训练并测试;
    • 零样本模型(zeroshot):在 19 个数据集上训练,在留出的第 20 个数据集上测试(对应论文中的零样本基数估计评估);
    • 微调模型(finetuned):加载预训练 checkpoint 后在目标数据集上微调。

模型以cardinality(或exec_time)为标签进行训练(见 constants.py 的LABELS),输入即本指南所介绍的查询图。

小结

  • CardBench 提供三个层次复杂度的训练查询图(单表/二表连接/多表连接),共覆盖 20 个数据库、每库数千至数万条查询实例;
  • 每个实例是以 SQL 查询为中心构建的异构图:节点类型含gtablesattributespredicatesopscorrelations,边类型含 8 类语义关系,并内嵌真实基数、执行时间与 SQL 字符串作为图级上下文;
  • 特征按属性类型选择性填充(字符串列用percentiles_100_string,数值列用percentiles_100_numeric),缺失统一用-1占位;
  • 读取数据仅需sparse-deferred+numpy,通过InMemoryDB.from_file(...)即可加载并访问节点特征与图级标签;
  • 数据集的生成代码、校验逻辑与配套的图 Transformer 模型均已在仓库中开源,可复现数据管线或直接训练模型。
  • 人工智能
  • 深度学习
  • NLP
  • 计算机视觉
  • 强化学习

【免费下载链接】google-research

Google Research

项目地址:https://gitcode.com/gh_mirrors/go/google-research
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 2:44:20

vim 光标十字定位不显示,TaoToken 接 Codex 查 cursorline 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 2:43:09

汽车操纵稳定性与平顺性建模实战:从习题到MATLAB/Python仿真

简介&#xff1a;本资源是《汽车理论》&#xff08;余志生第4版&#xff09;教材第5-6章配套习题的完整参考答案&#xff0c;专为车辆工程专业本科生、研究生及备考相关课程考试的学习者设计&#xff0c;聚焦汽车操纵稳定性与转向特性的核心计算与分析难点。PDF文件共1个&#…

作者头像 李华
网站建设 2026/9/20 2:40:21

Excel数据处理进阶:四大核心功能玩转筛选与汇总

天天用Excel的人&#xff0c;大多数都栽在“找数据”和“理数据”这两件事上。表格一过万行&#xff0c;眼睛扫过去根本看不过来&#xff0c;于是有人学会了自动筛选&#xff0c;以为万事大吉&#xff1b;等到领导要“各地区、各产品的分类汇总”&#xff0c;又开始手工统计&am…

作者头像 李华
网站建设 2026/9/20 2:38:52

SPSS相关性分析方法全解:从系数选择到偏相关实战

简介&#xff1a;SPSS相关性分析入门PDF适合数据分析初学者与科研人员&#xff0c;系统梳理了连续与分类变量组合下的五种核心方法&#xff1a;线性回归、独立样本T检验、逻辑回归、列联表分析及描述性统计&#xff0c;每种方法均涵盖适用条件、菜单操作步骤和输出结果解读。文…

作者头像 李华