我使用bigquery
从python
应用程序批处理insert
数据。表为摄入时的partitioned
。我看到的不同之处在于,我插入的数据在摄入后1.5小时后会出现query
。
后来我把schema
改成了timestamp
列
这一次,我可以在摄入后立即获得query
数据。
为什么表schema
中的_PARTITIONTIME
伪列与timestamp
列之间的行为存在差异?
蟒蛇吞食代码:
这是代码的简化版本:
bigquery_client = bigquery.Client()
TABLE_REF = bigquery_client.dataset('DATASET_ID').table('TABLE_ID')
TABLE = bigquery_client.get_table(TABLE_REF)
def ingest_to_bq(data: LIST[LIST]):
bigquery_client.insert_rows(TABLE, data)
表架构:
[
{
"name": "epoch_ms",
"type": "INTEGER",
"mode": "REQUIRED"
},
{
"name": "application_id",
"type": "STRING",
"mode": "REQUIRED"
},
{
"name": "ack_id",
"type": "STRING",
"mode": "REQUIRED"
},
{
"name": "data",
"type": "STRING",
"mode": "REQUIRED"
}
]
从BIGQUERY接口创建表,并在摄取时进行分区。
查询:
我使用BIGQUERY接口再次查询。
SELECT data from <DATASET_ID>.<TABLE_ID> WHERE _PARTITIONTIME="2020-03-30"
上面的查询不会显示半小时前摄入的结果。摄入后大约需要1.5小时才能得到结果。
新方案:
[
{
"name": "send_timestamp",
"type": "TIMESTAMP",
"mode": "REQUIRED"
},
{
"name": "application_id",
"type": "STRING",
"mode": "REQUIRED"
},
{
"name": "ack_id",
"type": "STRING",
"mode": "REQUIRED"
},
{
"name": "data",
"type": "STRING",
"mode": "REQUIRED"
}
]
查询新方案:
SELECT data from <DATASET_ID>.<TABLE_ID> WHERE send_timestamp>="2020-03-30 00:00:00" and send_timestamp<="2020-03-30 23:59:59"
此查询会在摄入后立即返回结果。我不必等待。
延迟的原因是BigQuery
的流缓冲区。流缓冲区是一种保留最近插入的行并针对写入吞吐量进行优化的缓冲区。换言之,当您将流式数据插入BigQuery
时,您的数据首先会插入流式缓冲区,在该缓冲区中最多停留90分钟。在这一点上,数据被认为是持久的,你可以查询它,但你不允许对它进行一些特定的操作
正如您在文档中看到的,当数据位于流缓冲区中时,_PARTITIONTIME
伪列将为NULL
。鉴于此,您的查询无法找到新插入的行,因为您的_PARTITIONTIME
是NULL
。为了确保最近插入的数据的伪列中的值是NULL
,可以运行下面的查询。
-
如果要查看所有行的伪列,请运行
SELECT *, _PARTITIONTIME p from <DATASET_ID>.<TABLE_ID>
-
如果要获取伪列为null的所有行,请运行
SELECT * from <DATASET_ID>.<TABLE_ID> WHERE _PARTITIONTIME is null
最后,我想为这个主题添加一些有用的参考资料。
- BigQuery分区表的引用
- BigQuery流引用
- 一篇关于流到BigQuery的官方文章,讨论了流缓冲区以及如何处理它
我希望它能帮助