ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

CardBench:关系数据库学习型基数估计基准——训练数据集构建流水线与查询图格式实战指南

CardBench:关系数据库学习型基数估计基准——训练数据集构建流水线与查询图格式实战指南 CardBench关系数据库学习型基数估计基准——训练数据集构建流水线与查询图格式实战指南【免费下载链接】google-researchGoogle Research项目地址: https://gitcode.com/gh_mirrors/go/google-researchCardBench 是一个面向关系数据库学习型基数估计Learned Cardinality Estimation的基准Benchmark其核心交付物有两类一是可直接用于训练和评估模型的带注释查询图Annotated Query Graphs训练数据集二是用于复现或生成新训练数据集的完整代码流水线。本文以 CardBench README 为主线结合仓库内的configuration.py、statistics_sql_tables_definition.sql、各流水线脚本与训练数据格式文档系统讲解 CardBench 的架构、五步数据处理流水线、配置方法、训练数据集格式以及读取查询图的完整实操。一、CardBench 是什么CardBench论文详见 arXiv: 2408.16170是一个专为关系数据库中学习型基数估计设计的基准。基数估计是查询优化器估算一条 SQL 查询尤其是含 JOIN 与过滤谓词的查询结果行数的核心步骤估计精度直接影响执行计划的质量。CardBench 的目标是为该领域提供规模化、多样化的训练数据与可复现的生成流程。仓库中 CardBench 由两部分构成训练数据集training datasets位于 training_datasets 目录包含 Single Table、Binary Join、Multi Join 三类查询图数据npz 文件以及对应的示意图。生成训练数据集的代码即仓库根目录下的各 Python 脚本与库目录用于在既有或全新数据集上复现现有训练数据或生成新的工作负载。CardBench 的两种使用方式训练或评估基数估计模型最常见直接使用已生成的查询训练图Query Training Graphs。这种方式不需要运行任何 CardBench 代码只依赖sparse-deferred、numpy等轻量依赖即可读取数据。查询图由不同复杂度的查询生成具体细节见 TrainingQueryGraphs.md。生成新工作负载 / 使用不同数据集需要运行 CardBench 代码完整走一遍从统计计算到查询图生成的流水线。二、CardBench 代码五步数据处理流水线CardBench 代码用于为基数估计生成训练数据集是一个多步骤流水线README 中给出的大致流程如下如有必要创建数据库的下采样版本down sampled versions计算表/列统计信息收集表与列信息、计算表与列统计量生成训练 SQL 查询运行查询以收集真实基数actual cardinalities创建训练数据集查询图由于运行整条流水线的成本较高作者计划在发布代码之外同时发布最终产物训练数据集并额外发布 CardBench 工作负载SQL 查询、数据集与数据集元数据统计信息、schema。原始数据以 CSV 文件提供仓库同时给出建表与从 CSV 导入数据的脚本已在 PostgreSQL 上测试通过。所有制品的下载方式见 DowloadArtifacts.md。三、通用信息与系统设置3.1 双数据库架构CardBench 收集或计算出的所有统计信息都存储在一组数据库表中供后续生成查询图与工作负载使用。整个系统围绕两类数据库展开数据数据库data database存放被收集基数的业务表即待估计基数的数据表。元数据/统计数据库metadata / statistics database存放计算得到的统计信息。这两类数据库可以存放在不同的系统中。从源码结构看这种双库设计体现在 calculate_statistics_and_save_to_database.py 的dbs字典中其中data_dbclient用于查询业务数据库metadata_dbclient用于存储统计结果run_queries.py 也采用了完全相同的dbs结构。3.2 数据库后端与连接器代码最初为BigQuery设计数据与元数据数据库均以 BigQuery 为后端。但仓库在 database_connector.py 中提供了一个可扩展的数据库连接器当前DBType枚举只包含BIGQUERYcreate_database_connection、run_query、table_exists、get_query_cardinality等接口均为按数据库类型分发的桥接函数可通过新增枚举值与对应的xxx_bigquery实现来扩展其他数据库。同时需要注意扩展数据库并不只是替换连接器——部分统计功能例如百分位数计算需要数据库提供 percentile SQL 函数或发现表 schema 需要调用数据库专有 API 返回列名与类型还需要修改流水线其他部分。3.3 初始化步骤使用 CardBench 代码前需要完成以下初始化运行 statistics_sql_tables_definition.sql 创建全部必要的统计表。该脚本定义了tables_info、columns_info、columns_stats、各类型的columns_*_extra_stats表、pk_fk、histograms_table等表结构脚本头部注释明确要求把project_name.dataset_name.替换为与configuration.py一致的项目与数据集名。更新 configuration.py 中的表 id 与有效文件路径。如果使用预计算统计precalculated statistics还需更新calculate_statistics_library/pre_calculated_statistics目录下文件中的表 id详见下文。3.4 configuration.py 关键配置项configuration.py 是整条流水线的配置中心其头部注释列出了使用前必须替换的四类内容。核心配置项包括配置项作用默认占位DATA_DBTYPE/METADATA_DBTYPE数据库与元数据库类型需替换为database_connector.DBType.XNoneTABLES_INFO_TABLE等统计表名各统计结果存储表需替换X.为project_name.dataset_nameX.tables_info等SAMPLE_PROJECTNAME_DATASET_NAME_4K4k 行样本表数据集名用于皮尔逊相关性计算X_sampled_tablesWORKLOAD_DEFINITION_TABLE存储工作负载定义workload id 与生成参数X.workload_definitionQUERY_RUN_INFORMATION_TABLE存储查询执行结果SQL 与真实基数X.query_run_informationDIRECTORY_PATH_JSON_FILESJSON 统计文件目录NoneDIRECTORY_PATH_QUERY_FILES工作负载查询文件目录NoneDIRECTORY_TRAINING_QUERYGRAPH_OUTPUT训练查询图输出目录NonePROJECT_NAME/DATASET_NAMES待处理数据数据库的项目名与数据集名列表[]此外TYPES_TO_TABLES将各列类型INT64、FLOAT64、NUMERIC、STRING、DATE等映射到对应的额外统计表TYPES_TO_COLLECT_STATS将列类型映射为 definitions.py 中Datatype枚举INT、FLOAT、NUMERIC、STRING、DATE 等is_type_we_dont_collect_stats()则识别 ARRAY、STRUCT、GEOGRAPHY、JSON、BOOLEAN 等不采集统计信息的列类型。四、步骤一计算统计Calculate Statistics流水线第一步是计算统计信息并收集数据库信息由 calculate_statistics_and_save_to_database.py 执行相关代码位于calculate_statistics_library。从源码看对每个数据集依次执行以下子步骤见 calculate_statistics_and_save_to_database.pycollect_and_write_table_information收集表级信息collect_and_write_column_information收集列级信息列名、类型calculate_and_write_column_statistics计算列统计如null_frac、num_unique、row_countcalculate_and_write_extra_column_statistics按类型计算额外统计calculate_and_write_percentiles计算百分位数依赖数据库的 percentile 函数calculate_and_write_unique_values统计唯一值calculate_and_write_frequent_words统计字符串列高频词calculate_and_write_column_histograms计算列直方图create_table_samples_fixsize(..., target_row_number4000)创建 4000 行定长样本表calculate_and_write_pearson_correlation在样本表上计算列间皮尔逊相关性4.1 预计算统计Precalculated Statistics由于该步骤复现成本较高作者同时发布了已收集的统计结果下载方式见 DowloadArtifacts.md。calculate_statistics_library/pre_calculated_statistics/pk_fk.sql用于将主键与外键信息插入configuration.PK_FK_TABLE表。五、步骤二生成查询Generate Queries查询生成器基于此前发布的 zero-shot cost estimation 查询生成器改造而来修改版见 generate_queries_library/query_generator.py。generate_queries_and_save_to_file.py 生成查询并一行一条写入文件生成器参数直接在该文件内定义。一个查询文件即一个工作负载workload每个工作负载由整数workload id标识workload id 与生成参数一起存储在configuration.WORKLOAD_DEFINITION_TABLE表中。5.1 查询生成器的输入JSON 统计文件查询生成器接收一组 JSON 文件内含目标数据库的 schema、列统计与字符串列统计。这些 JSON 可通过 save_dataset_statistics_to_json_files.py 从calculate_statistics_and_save_to_database.py收集的统计结果转换而来。为方便试验仓库已内置生成好的 JSON 文件generate_queries_library/dataset_statistics_jsons目录。如果直接使用现有 JSON 文件则可以跳过计算统计和保存统计到 JSON两步直接开始生成查询。5.2 路径配置JSON 文件存放在configuration.DIRECTORY_PATH_JSON_FILES指定的目录工作负载查询文件存放在configuration.DIRECTORY_PATH_QUERY_FILES指定的目录六、步骤三执行查询Execute Queriesrun_queries.py 接收一个参数workload id即 Generate Queries 阶段生成的工作负载查询文件的整数标识符。代码读取该工作负载中的全部查询并逐条执行源码中workload_id_to_run argv[1]未传参时会打印用法提示见 run_queries.py。执行结果存储在configuration.QUERY_RUN_INFORMATION_TABLE表中每条记录包含查询的 SQL 字符串查询的真实基数cardinalityworkload id用于标识所属工作负载query run id一次运行的整数标识符。每次运行一个工作负载都会创建一个新的 run因此同一工作负载被多次运行时会产生多个 query run。七、步骤四生成带注释的查询图Generate Annotated Query Graphsgenerate_training_querygraphs_and_save_to_file.py 是整个流程的最后一步。查询执行完成后SQL 查询被翻译为图结构并用数据集统计信息进行注释转换链为SQL 字符串 → 关系运算符relational operators→ 查询计划query plan→ 图graph生成的图以sparse_deferred 格式保存为.npz文件。八、CardBench 训练数据集Training Datasets训练数据集的完整说明见 TrainingQueryGraphs.md。每个训练实例training instance是一条被表示为带注释图的 SQL 查询通过在 Google BigQuery 上执行查询获得真实基数并作为上下文context包含在图中使用的 SQL 查询本身也包含在图的上下文中。8.1 三类训练数据集数据集查询构成Single Table单表上的 1–4 个过滤谓词Binary Join两表连接每表 1–3 个过滤谓词Multi Join1–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;8.2 文件命名与数据集规模文件命名规则为database_name_single_table/binary_join/multi_join.npz。数据库名中出现~表示该库已做下采样down sampled。仓库文档给出了 20 个数据集的表数量与各类查询图数量数据集# 表# Single Table# Binary Join# Multi-Joinaccidents39125845429242airline1965681309610467consumer35961557111857employee6126751041711041movielens13144881575717067sample_cms_synthetic_patient_data_omop249574653610038sample_covid19_weathersource_com493661018616075sample_crypto_bitcoin_cash2143151240417114sample_ethereum_blockchain7197561742419962sample_geo_openstreetmap16163461500010979sample_github_repos95268451310564sample_human_variant_annotation26138621408512162sample_idc_v10198609646412081sample_open_targets_genetics139734905810025sample_samples888931136910832sample_stackoverflow14143051277311399sample_usfs_fia11138221178710980sample_uspto_oce_claims125925612311968sample_wikipedia256659737510739tpch_10G81172713181163188.3 训练数据 Schema每个训练实例是一个异构图heterogeneous graph节点类型包括g图级节点、tables、attributes、predicates、ops、correlations边类型如下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) # 相关性-谓词主要节点特征图级节点 gcardinality真实基数、exec_time执行时间、query_id、querySQL 字符串tablesrows行数、nameattributesnull_frac、num_unique、data_type、name、percentiles_100_numeric、percentiles_100_string、min_numeric/max_numeric、min_string/max_stringpredicatespredicate_operator、estimated_selectivity、offset、constant、encoded_constantopsoperator如scan、joincorrelationstype、correlation、validity注意特征根据属性类型填充——字符串类型属性填充percentiles_str与字符串极值数值属性填充percentiles_num与数值极值未填充的特征统一用-1填充例如示例中字符串列的percentiles_100_numeric全为-1。九、如何读取训练数据Python 实操训练数据使用 Sparse Deferred 库定义的 Graph Struct 编码。Sparse Deferred 提供了一套简洁的写入、读取与存储接口并可将数据序列化为 TF/JAX 友好的格式。运行示例代码需要Python 3.10、sparse-deferred、numpy均可通过 pip 安装。9.1 加载数据集from sparse_deferred.structs import graph_struct GraphStruct graph_struct.GraphStruct InMemoryDB graph_struct.InMemoryDB # 训练数据集按分片sharded存储即拆分为多个文件 # 加载 consumer_single_table 数据集 filename single_table/consumer_single_table.npz db InMemoryDB.from_file(filename)9.2 查看实例数量与 schema# 打印训练实例数量 print(Number of training instances:, db.size) # Number of training instances: 5571 # 打印训练实例的 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)}9.3 查看节点类型与特征first_training_example db.get_item(0) # 打印节点类型 print(Node types:, first_training_example.nodes.keys()) # Node types: dict_keys([g, tables, attributes, predicates, ops, # correlations]) # 打印表节点特征 print(Table node features:, db.get_item(0).nodes[tables].keys()) # Table node features: dict_keys([rows, name]) # 打印边类型 print(Edge types:, first_training_example.edges.keys())9.4 读取表级信息# 打印第一个表节点的行数与名称 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: bbq-cost-models-exp.consumer.HOUSEHOLDS9.5 读取图级信息基数、执行时间、查询# 打印查询基数、查询、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: bSELECT 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从上述输出可以看出该示例是一个包含两表 JOIN 的查询真实基数为 824130执行时间 2390 毫秒图中tables.rows直接给出了两张表的行数340872 与 824130attributes节点携带null_frac、num_unique、百分位数等统计特征未使用的特征以-1填充——这些信息正是训练学习型基数估计模型所需的输入信号。十、CardBench 制品下载指南DowloadArtifacts.md 列出了四类可下载制品均托管在 Google Cloud Storage 的gresearch/CardBench_zero_shot_cardinality_training目录下数据集 CSV各数据集的原始数据 CSV 文件。建表脚本create_schema_scripts每个数据集对应一个*_create_tables_pg_oss.sql脚本用于在 PostgreSQL 兼容数据库中创建表如accidents_create_tables_pg_oss.sql、tpch_10G_create_tables_pg_oss.sql等 20 个数据集。拷贝脚本copy_to_db_scripts*_copy_to_postgres.sql用于把 CSV 导入对应表。脚本中包含DATASET_PATH_PREFIX占位符使用前需替换为下载 CSV 文件所在父目录的实际路径。数据集元数据datasets_metadata每个数据集三个 JSON 文件dataset.schema.json、dataset.column_statistics.json、dataset.string_statistics.json——这些正是查询生成器所需的输入 JSON。训练查询图cardbench_query_graphs_for_github按single_table/、binary_join/、multi_join/三个目录组织文件名为dataset_type.npz共 20 数据集 × 3 类型。这些脚本与 JSON 与本文介绍的代码流水线一一对应建表脚本对应数据数据库的初始化元数据 JSON 对应查询生成阶段输入查询图 npz 对应最终训练数据。十一、小结与最佳实践综合 README.md、TrainingQueryGraphs.md 与 DowloadArtifacts.md 的内容使用 CardBench 的建议路径如下仅训练/评估模型直接下载查询图 npz用 Sparse Deferred 的InMemoryDB.from_file读取无需运行任何流水线代码——这是大多数研究者的首选路径。复现现有工作负载下载数据集 CSV 与元数据 JSON若使用仓库内置 JSON 可跳过统计计算随后依次运行generate_queries_and_save_to_file.py→run_queries.py→generate_training_querygraphs_and_save_to_file.py。全新数据集先运行statistics_sql_tables_definition.sql建表并更新configuration.py再运行calculate_statistics_and_save_to_database.py走完整条流水线。无论哪条路径都需要注意预计算统计/内置 JSON 可以显著降低复现成本BigQuery 是开箱即用的后端扩展到其他数据库需自行扩展 database_connector.py 中的分发函数并补齐百分位数等数据库特有功能。【免费下载链接】google-researchGoogle Research项目地址: https://gitcode.com/gh_mirrors/go/google-research创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表