在摄取时分区时,Bigquery 中的数据查询延迟的原因是什么?

Moh*_*taz 3 google-bigquery

我用来bigquery批量处理insert我的应用程序中的数据python。这些表格是partitioned在摄入时间。我看到的差异是我插入的数据会在query摄入后 1.5 小时后出现。

后来我改了schema一个timestamp专栏

这次我可以query在摄入后立即获取数据。

为什么表中的_PARTITIONTIME伪列与列之间的行为存在差异?timestampschema

用于摄取的 Python 代码:

这是代码的简化版本:

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)
Run Code Online (Sandbox Code Playgroud)

表架构:

[
    {
        "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"
    }
]
Run Code Online (Sandbox Code Playgroud)

从 BIGQUERY 接口创建表并在摄取时进行分区。

询问:

我使用 BIGQUERY 接口再次查询。

SELECT data from <DATASET_ID>.<TABLE_ID> WHERE _PARTITIONTIME="2020-03-30"
Run Code Online (Sandbox Code Playgroud)

上面的查询不会显示半小时前摄取的结果。摄入后大约需要 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"
    }
]
Run Code Online (Sandbox Code Playgroud)

查询新模式:

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"
Run Code Online (Sandbox Code Playgroud)

该查询在摄取后立即返回结果。我不必等待。

rme*_*ves 7

造成这种延迟的原因是BigQuery缓冲区。流缓冲区是保留最近插入的行并针对写入吞吐量进行优化的缓冲区。换句话说,当您将流数据插入到流数据中时,数据首先会插入到流缓冲区中,并在其中最多保留 90 分钟。此时,数据被认为是持久的,您可以查询它,但不允许您对其执行某些特定操作。BigQuery

正如您在文档中看到的,当您的数据位于流缓冲区中时,您的_PARTITIONTIME伪列将是NULL。鉴于此,您的查询无法找到新插入的行,因为您的_PARTITIONTIMENULL。为了确保值位于NULL最近插入的数据的伪列中,您可以运行下面的查询。

  1. 如果您想查看所有行的伪列,请运行SELECT *, _PARTITIONTIME p from <DATASET_ID>.<TABLE_ID>

  2. 如果要获取伪列为空的所有行,请运行SELECT * from <DATASET_ID>.<TABLE_ID> WHERE _PARTITIONTIME is null

最后,我想为这个主题添加一些有用的参考资料。

  1. BigQuery 分区表的参考
  2. BigQuery 流式处理参考
  3. 关于流式传输到 BigQuery 的官方文章,其中讨论了流式缓冲区以及如何处理它。

我希望它有帮助