如何通过Python用本地CSV更新BigQuery表?含性能成本优化疑问
BigQuery raw_stock表更新方案对比与优化建议
一、全表WRITE_TRUNCATE覆盖的优劣势
- 优点:
- 上手快:直接导出MySQL全表CSV,用
WRITE_TRUNCATE加载就行,不用写复杂的更新逻辑 - 速度够快:批量加载的速度甩逐行更新几条街,2000条全量数据加载最多几十秒,比逐行的17分钟强太多
- 成本更低:BigQuery批量加载的计费远低于大量单条更新,单条更新会占用更多资源,累积成本很高
- 上手快:直接导出MySQL全表CSV,用
- 缺点:
- 有数据窗口风险:覆盖过程中目标表会短暂空数据,如果下游有依赖这个表的查询,可能报错
- 冗余传输:每天只有2000条要更新,全量导出会传大量重复数据,浪费带宽和临时存储
- 增量丢失风险:如果导出MySQL全表和加载到BigQuery之间,MySQL有新数据写入,这部分会被覆盖(除非导出时用快照锁)
二、逐行更新的问题
- 速度太慢:2000条要17分钟,效率极低
- 成本高:每条更新都是独立DML,BigQuery按操作量计费,累计下来比批量操作贵很多
- 容易出问题:中间某条失败就得加重试逻辑,代码更复杂
三、更推荐的折中方案:批量MERGE更新
既然你已经有只含更新行的CSV,不如把它加载到BigQuery临时表,然后用一条MERGE语句批量更新,步骤如下:
- 把本地更新CSV加载到BigQuery临时表(比如
temp_raw_stock_updates),用WRITE_TRUNCATE覆盖临时表 - 执行MERGE语句,通过
id_store和id_product匹配,更新目标字段:
MERGE INTO `你的项目.你的数据集.raw_stock` AS target USING `你的项目.你的数据集.temp_raw_stock_updates` AS source ON target.id_store = source.id_store AND target.id_product = source.id_product WHEN MATCHED THEN UPDATE SET product_amount = source.product_amount, date_update = source.date_update
- 可选:用完临时表就删掉
这个方案的好处:
- 速度快:批量加载加单条MERGE,全程几十秒搞定
- 成本低:就一次加载加一次DML,比逐行更新省不少钱
- 数据安全:MERGE是原子操作,不会出现表空的情况,也不会丢增量数据
- 代码简单:不用写循环处理每条数据,逻辑清晰
四、方案怎么选
- 如果
raw_stock表数据量很小(几万条以内),全表覆盖方案可以用,简单省事,但导出时记得用mysqldump --single-transaction这类快照方式,避免数据不一致 - 如果表数据量大,或者下游对表可用性要求高,优先用批量MERGE更新方案,兼顾速度、成本和数据一致性
内容的提问来源于stack exchange,提问作者newuser2255
相关产品推荐
相关产品推荐

