BigQuery使用Write_Truncate写入ingestion time分区表时误覆盖全部分区
解决BigQuery Ingestion Time分区表误覆盖全表问题
问题根源
- 你的表是Ingestion Time分区表,这类分区的
_PARTITIONTIME由BigQuery根据数据加载时间自动分配,无法通过表名$分区日期的方式直接指定写入分区,你的写法本质上不适用该分区类型。 - 加载数据时在
LoadJobConfig中重复设置time_partitioning参数,会覆盖原有表的分区配置,导致全表被重新分区;再加上WRITE_TRUNCATE的写入模式,最终清空了所有原有数据,并将新数据的摄入时间设为当前加载时间。
解决方案
方案一:改用基于字段的时间分区表(推荐)
如果可以调整表的分区类型,建议改成按业务时间字段(比如event_time)分区,这样就能精准控制写入/覆盖指定分区,操作更直接:
part_date = '$20241003' job_config = bigquery.LoadJobConfig( write_disposition=bigquery.WriteDisposition.WRITE_TRUNCATE, schema=options.schema, ) # 指定分区表名直接写入 table = bigquery.Table(f"{self._client.project}.{options.dataset}.{options.table_name}{part_date}") table.require_partition_filter = options.require_partition_filter self._client.load_table_from_dataframe( options.dataframe, table, job_config=job_config, ).result()
注意:表必须是预先创建的基于字段的时间分区表,不能是Ingestion Time分区表。
方案二:保留Ingestion Time分区表的处理方式
如果必须保留Ingestion Time分区,可通过「先删后插」的方式覆盖指定分区,比MERGE更简洁:
- 删除目标分区的原有数据:
partition_timestamp = "TIMESTAMP('2024-10-03')" delete_query = f""" DELETE FROM `{self._client.project}.{options.dataset}.{options.table_name}` WHERE _PARTITIONTIME = {partition_timestamp} """ self._client.query(delete_query).result()
- 将数据写入目标分区(通过临时表中转,确保
_PARTITIONTIME符合预期):
# 先把DataFrame写入临时表 temp_table = bigquery.Table(f"{self._client.project}.{options.dataset}.temp_load_table") self._client.load_table_from_dataframe(options.dataframe, temp_table).result() # 插入到指定Ingestion Time分区 insert_query = f""" INSERT INTO `{self._client.project}.{options.dataset}.{options.table_name}` PARTITION(_PARTITIONTIME = TIMESTAMP('2024-10-03')) SELECT * FROM `{temp_table.full_table_id}` """ self._client.query(insert_query).result() # 清理临时表 self._client.delete_table(temp_table)
内容的提问来源于stack exchange,提问作者Franco Hauva
相关产品推荐
相关产品推荐

