
Data Engineering Zoomcamp Module 3 作业实战指南BigQuery 数据仓库与 GCS 外部表全流程演练【免费下载链接】data-engineering-zoomcampData Engineering Zoomcamp is a free 9-week course on building production-ready data pipelines. Join the course here 项目地址: https://gitcode.com/GitHub_Trending/da/data-engineering-zoomcamp本篇实战指南以 Data Engineering Zoomcamp 2027 队列 Module 3Data Warehousing BigQuery的课后作业为核心骨架完整覆盖从纽约出租车数据上传 GCS、创建外部表、构建普通表与分区聚簇表到逐题解答九道 BigQuery 查询作业的全过程。读完本文你将掌握 BigQuery 外部表与物化表的区别、列式存储与扫描字节数估算的底层原理、分区与聚簇的选型策略并能在自己的 GCP 项目中复现这套数据仓库实验。作业概览与数据集说明本次作业的核心素材是2024 年 1 月至 6 月的 Yellow Taxi Trip Records注意并非全年数据仅上半年 6 个月。数据以 Parquet 格式提供来源为纽约市出租车与礼车委员会NYC TLC公开数据集。作业目标可拆解为四个层次数据装载将 6 个月 Parquet 文件下载并上传到自己的 GCS Bucket表结构搭建在 BigQuery 中创建外部表external table与普通物化表non-partitioned table查询实战通过九道题目验证对计数、列式存储、分区聚簇、字节估算等核心概念的理解提交验收将解答SQL、Shell 或代码提交到公开代码托管仓库并在作业表单中提供仓库链接。需要特别注意的约束作业明确要求如果使用 Kestra、Mage、Airflow、Prefect 等编排工具不要通过编排器把数据写入 BigQuery——数据加载应直接完成避免引入不必要的中间环节干扰实验结果。开始前务必确认GCS Bucket 中已出现全部 6 个文件。创建外部表时必须使用PARQUET 格式选项与课程中演示的 CSV 外部表不同。将数据装载到 GCS Bucket方案一使用 Python 脚本load_yellow_taxi_data.py作业目录提供了开箱即用的加载脚本 load_yellow_taxi_data.py。该脚本的核心流程如下鉴权通过服务账号 JSON 文件初始化 GCS 客户端默认读取当前目录下的gcs.json如果你已通过 Google Cloud SDK 登录可以注释掉这两行改用storage.Client(project...)方式。创建 Bucket调用create_bucket()检查 Bucket 是否存在、是否属于当前项目不存在则自动创建若 Bucket 名称已被占用且不可访问脚本会退出并提示更换名称。并发下载使用ThreadPoolExecutor(max_workers4)从https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2024-month.parquet并行下载 1-6 月共 6 个 Parquet 文件到本地。并发上传再次以 4 线程并发将文件上传到 GCS设置 8 MB 分块大小CHUNK_SIZE并带 3 次重试与存在性校验verify_gcs_upload。使用前需要修改的关键配置# 替换为你自己的 Bucket 名称 BUCKET_NAME dezoomcamp_hw3_2025 # 若已通过 GCP SDK 鉴权可注释掉下面两行 CREDENTIALS_FILE gcs.json client storage.Client.from_service_account_json(CREDENTIALS_FILE)运行方式在脚本所在目录执行python load_yellow_taxi_data.py运行结束后GCS Bucket 中应出现 6 个文件yellow_tripdata_2024-01.parquet至yellow_tripdata_2024-06.parquet。方案二使用 DLT 笔记本DLT_upload_to_GCP.ipynb如果你更习惯 Notebook 方式可以使用同一目录下的 DLT_upload_to_GCP.ipynb基于 dltdata load tool库完成同样的下载与上传流程。两种方案任选其一即可。权限前提无论采用哪种方案都需要生成一个具备 GCS Admin 权限的服务账号或已通过 Google Cloud SDK 完成鉴权。方案三备选extras/中的独立脚本模块还提供了不依赖编排器的备选工具 extras/其将 NYC TLC 的 CSV 下载后转为 Parquet 并上传 GCS使用uv管理依赖cd cohorts/2027/03-data-warehouse/extras uv sync uv run python web_to_gcs_with_progress_bar.py # 带进度条版本 uv run python web_to_gcs.py # 简洁版本BigQuery 环境搭建外部表与普通表数据就绪后在 BigQuery 中完成两张基础表的创建。第一步创建外部表External Table外部表的特点是数据仍存放在 GCSBigQuery 只保存元数据与 Schema。创建外部表后打开表详情可以看到长期存储为 0 字节、表大小为 0 字节、行数为 0——因为数据根本不在 BigQuery 内部参见 01-data-warehouse-and-bigquery.md 中对外部表特性的讲解。CREATE OR REPLACE EXTERNAL TABLE 你的项目.你的数据集.external_yellow_tripdata OPTIONS ( format PARQUET, uris [gs://你的bucket名/yellow_tripdata_2024-*.parquet] );注意与课程示例 big_query.sql 中 CSV 外部表的差异本次作业数据集是 Parquet 文件因此format必须写为PARQUET。第二步创建普通物化表非分区非聚簇CREATE OR REPLACE TABLE 你的项目.你的数据集.yellow_tripdata_non_partitioned AS SELECT * FROM 你的项目.你的数据集.external_yellow_tripdata;这条语句会把 GCS 中的数据真正复制进 BigQuery 存储因此执行需要一定时间。不要对该表做分区或聚簇它将成为后续对比实验的“对照组”。九道作业逐题解析说明以下题目均为选择题或简答题具体答案依赖你的实际数据建议结合运行结果验证。下文给出每道题的考察点、参考 SQL 与解题思路。Question 1统计记录总数题目2024 年 Yellow Taxi 数据共有多少条记录备选项为 65,623 / 840,402 / 20,332,093 / 85,431,289。参考 SQLSELECT count(*) FROM 你的项目.你的数据集.external_yellow_tripdata;在外部表上执行COUNT(*)BigQuery 会扫描全部 6 个月 Parquet 文件并返回总行数。六个月的纽约黄色出租车数据总量在千万级本题答案约为20,332,093请以你自己表上的实际查询结果为准。Question 2外部表与普通表的数据读取量估算题目对整份数据集统计PULocationID的 distinct 数量分别在外部表和普通表上执行估算的扫描数据量各是多少参考 SQLSELECT COUNT(DISTINCT PULocationID) FROM 你的项目.你的数据集.external_yellow_tripdata; SELECT COUNT(DISTINCT PULocationID) FROM 你的项目.你的数据集.yellow_tripdata_non_partitioned;考察点理解外部表与物化表的扫描行为差异。外部表的数据在 GCSBigQuery 需要把 Parquet 文件拉进来才能统计而普通表是 BigQuery 原生存储同样要全表扫描两列中的一列。正确答案为0 MB for the External Table and 155.12 MB for the Materialized Table——外部表上的估算值为 0查询尚未真正执行时 BigQuery 无法精确预知 GCS 数据规模普通表则需扫描约 155.12 MB。Question 3理解列式存储题目在普通表上分别查询PULocationID一列、以及PULocationIDDOLocationID两列为什么两次的估算字节数不同正确答案BigQuery 是列式columnar数据库只扫描查询中涉及的具体列。查询两列PULocationID, DOLocationID需要读取的数据比查询一列PULocationID更多因此估算的处理字节数更高。原理深化这一行为源于 BigQuery 的底层存储架构。课程 04-internals-of-bigquery.md 指出BigQuery 采用列式存储该组件被称为 Polymer每一列独立存放一行的数据会散布在多个位置而不是像 CSV 那样按行整体存放。列式存储使得按列聚合极快而数据仓库场景下我们很少同时查询所有列——这正是SELECT *代价高昂的根本原因也是最佳实践中“避免SELECT *、只取所需列”这一建议的底层逻辑见 03-bigquery-best-practices.md。Question 4统计零车费记录数题目fare_amount等于 0 的记录有多少条备选项为 128,210 / 546,578 / 20,188,016 / 8,333。参考 SQLSELECT count(*) FROM 你的项目.你的数据集.yellow_tripdata_non_partitioned WHERE fare_amount 0;考察点对物化表执行带过滤条件的聚合。结合 Q1 的总行数约 2000 万零车费记录数远小于总数答案应为128,210请以实际查询结果为准。Question 5分区与聚簇的选型策略题目如果查询总是按tpep_dropoff_datetime过滤、并按VendorID排序最佳建表策略是什么正确答案Partition bytpep_dropoff_datetimeand Cluster onVendorID。参考 SQL创建新表CREATE OR REPLACE TABLE 你的项目.你的数据集.yellow_tripdata_partitioned_clustered PARTITION BY DATE(tpep_dropoff_datetime) CLUSTER BY VendorID AS SELECT * FROM 你的项目.你的数据集.external_yellow_tripdata;原理深化为什么不能两者都做分区课程 02-partitioning-vs-clustering.md 明确说明分区只能基于单个列而聚簇可指定最多 4 列。更关键的是选型逻辑成本可预知性分区的收益在执行前已知——过滤分区列的查询只会读取部分分区聚簇的收益要等查询运行完才知道。因此当你想用SETmax_bytes_billed 之类的上限控制成本时只能依赖分区粒度当需要比分区更细的过滤粒度时用聚簇管理能力分区支持按分区删除、跨存储迁移等分区级管理聚簇没有基数列的分区基数distinct 值数量过高会触及每表 4000 个分区的上限此时应改用聚簇。本场景中日期过滤适合分区粒度是天然的VendorID 基数低、适合作为聚簇键故答案为“按tpep_dropoff_datetime分区 按VendorID聚簇”。Question 6分区带来的收益对比题目查询tpep_dropoff_datetime在 2024-03-01 至 2024-03-15含边界之间的 distinctVendorID。先在普通表上执行并记录估算字节数再换成分区聚簇表执行两次的估算值各是多少参考 SQLSELECT DISTINCT(VendorID) FROM 你的项目.你的数据集.yellow_tripdata_non_partitioned WHERE DATE(tpep_dropoff_datetime) BETWEEN 2024-03-01 AND 2024-03-15; SELECT DISTINCT(VendorID) FROM 你的项目.你的数据集.yellow_tripdata_partitioned_clustered WHERE DATE(tpep_dropoff_datetime) BETWEEN 2024-03-01 AND 2024-03-15;正确答案310.24 MB for non-partitioned table and 26.84 MB for the partitioned table。原理深化普通表必须扫描全表 6 个月的数据约 310 MB分区表只读取 3 月上半月对应的分区扫描量骤降到约 26.84 MB——这就是**分区裁剪partition pruning**的直接体现。课程演示big_query.sql中 2019 年 6 月数据也呈现同样规律非分区表扫描 1.6 GB分区表仅扫描约 106 MB。Question 7外部表的数据存储位置题目外部表的数据实际存储在哪里正确答案GCP Bucket。原理深化外部表只把 Schema 与元数据登记在 BigQuery数据本体始终位于 GCS 的 Parquet 文件中。这也是为什么外部表详情页显示 0 字节、0 行——BigQuery 无法在不扫描的情况下获知外部数据的行数与大小。理解这一点对成本管理很重要频繁查询外部表需要反复从 GCS 拉取数据比查 BigQuery 原生存储更昂贵03-bigquery-best-practices.md 中亦提示“外部数据源要适度使用不要过度”。Question 8聚簇是否总是最佳实践题目BigQuery 中“总是对数据做聚簇”是最佳实践吗正确答案False。原理深化课程 02-partitioning-vs-clustering.md 明确指出聚簇并非免费小于 1 GB 的小表上分区和聚簇都无法带来显著的查询性能提升反而会因元数据读取与维护增加额外成本。此外聚簇/分区还会带来以下代价与限制分区上限为每表 4000 个分区基数过大会触及上限聚簇列必须是顶层非重复列且类型限于 DATE、BOOLEAN、GEOGRAPHY、INT64、NUMERIC、STRING、DATETIME频繁写入如每几分钟且波及大部分分区的变更操作会削弱聚簇的排序收益虽然 BigQuery 会自动在后台执行重聚簇reclustering以恢复排序特性该过程不收费、不影响查询性能。因此正确姿势是根据查询模式按需选择小表与低价值场景完全可以不做分区聚簇。Question 9不计分理解表扫描题目在普通表上执行SELECT count(*)BigQuery 估算会读取多少字节为什么参考 SQLSELECT count(*) FROM 你的项目.你的数据集.yellow_tripdata_non_partitioned;解题思路本题虽不计分但直指 BigQuery 的元数据优化核心。COUNT(*)这类统计行数的查询BigQuery 可以直接读取表的元数据行数信息给出结果无需扫描任何列数据因此估算扫描字节数为 0 或极小。这与 Q2 中COUNT(DISTINCT PULocationID)必须真实扫描数据形成鲜明对比——distinct 计数需要读取列值才能去重而纯行数统计走的是元数据捷径。这是理解“估算字节数 ≠ 表大小”的最佳案例。提交与学习分享完成九道题后将解答整理并提交若解答以SQL 或 Shell 命令形式为主直接在仓库的 README 中给出即可若涉及 Python 等代码文件将代码放入公开仓库GitHub 或其他代码托管平台提交作业时一并附上仓库链接。作业表单地址与 2027 队列的提交入口以课程官方通知为准历史上该模块提交地址为 DataTalks Club 课程站点的 Homework 3 表单。课程方鼓励“Learning in Public”分享。作业文档中提供了 LinkedIn 与 Twitter/X 的示例文案模板核心要点是总结本周学到的能力创建 GCS 外部表、构建 BigQuery 物化表、分区与聚簇调优、理解列式存储与查询优化、基于 2000 万 记录的 NYC 出租车数据做规模化分析并附上自己的作业仓库链接。你也可以参考 README.md 中社区成员分享的笔记风格。参考资料与延伸阅读本模块完整讲义01-data-warehouse-and-bigquery.md外部表、分区、聚簇的图文讲解分区与聚簇选型02-partitioning-vs-clustering.md成本与性能最佳实践03-bigquery-best-practices.mdBigQuery 内部原理04-internals-of-bigquery.md课程配套 SQLbig_query.sql历史作业参考big_query_hw.sql数据加载脚本load_yellow_taxi_data.py、DLT_upload_to_GCP.ipynb、extras/【免费下载链接】data-engineering-zoomcampData Engineering Zoomcamp is a free 9-week course on building production-ready data pipelines. Join the course here 项目地址: https://gitcode.com/GitHub_Trending/da/data-engineering-zoomcamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考