【问题标题】:BigQuery: Create View using ROW_NUMBER function breaks partition filter policyBigQuery:使用 ROW_NUMBER 函数创建视图会破坏分区过滤策略
【发布时间】:2021-12-11 20:30:15
【问题描述】:

我们在 BQ 中创建了一个表,“TS”列在创建表时用作分区列,例如“PARTITION BY DATE(TS)”。我们设置“require_partition_filter=true”

当我们创建如下视图时,视图上的查询可以工作:

CREATE OR REPLACE VIEW mydataset.test_view AS select * from 
mydataset.test_table
--query based on view
select * from mydataset.test_view where TS > TIMESTAMP("2021-09-05 08:30:00")

但是,如果我们在视图创建语句中添加 ROW_NUMBER() 函数,视图上的相同查询会引发错误:

CREATE OR REPLACE VIEW mydataset.test_view AS 
select *, ROW_NUMBER() over (
partition by ID
order by ID, TS
) as row_number from mydataset.test_table
--query based on view return error
select * from mydataset.test_view where TS > TIMESTAMP("2021-09-05 08:30:00")
--error msg: Cannot query over table without a filter over column(s) 'TS' 
that can be used for partition elimination

这是什么原因,有什么可用的解决方案?欣赏任何想法/想法。谢谢。

更新: 我们还尝试在视图创建中添加“位置”。但是,对于我们的案例,我们不能限制通过视图暴露的真实数据时间范围,用户希望能够从视图中查询所有数据。这意味着我们只能过滤具有始终为真条件的 TS,例如“TS 不为空”或“TS > TIMESTAMP("1970-01-01 00:00:00")。”这样,view on view 不会报错,但性能很差,因为即使我们在 view 上查询时添加了额外的 TS 过滤器,在执行查询时实际上也没有进行分区修剪。

【问题讨论】:

  • 这与表的分区有关。建表时是否在分区中使用了 TS 列?
  • @Mr.Batra :是的,TS 在创建表时用作分区列,例如“PARTITION BY DATE(TS)”。我们设置“require_partition_filter=true”
  • 您必须在视图本身内添加“where”。
  • @Mr.Batra:但是为什么第一个视图创建语句可以工作?它在视图中也没有“位置”。我们希望向用户公开视图并使用户能够决定 TS 条件而不是硬编码视图中的周期。
  • 尝试从视图中删除行号并将其添加到从视图中选择。

标签: google-bigquery partition row-number


【解决方案1】:

视图实际上只是原始分区表的子查询。您的第一条语句有效,因为创建的视图查询 在分区字段 ts 上被过滤掉了。来自视图查询的过滤器被传递到分区表。似乎 BigQuery 认识到 SELECT * 只是返回完整表,因此它必须完全绕过该步骤,因此它实际上不会返回整个分区表。

第二个不起作用的原因是因为创建的视图查询

ROW_NUMBER() over (partition by ID order by ID, TS)

正在查询 over 子句中的整个分区表(意味着它没有被 过滤,这是分区表所需要的),因为它尚未评估数据的 WHERE,因为它正在创建自己的命名窗口中的分区。

【讨论】:

    【解决方案2】:

    根据doc,当您启用 require_partition_filter=true 时,当您尝试在没有 WHERE 子句的情况下查询表时,它会引发您遇到的错误。

    从您创建的第一个视图和查询中,您已经传递了 where 子句,因此您将获得输出。

    在第二个视图中,您添加了 ROW_NUMBER() 函数,当查询该视图时,您会收到错误消息。由于您在查询中传递的过滤条件而发生错误。

    我尝试使用一组样本数据来复制您的问题。解决方法是使用 Where 条件创建一个视图(使用源表中的数据子集),然后根据需要查询该视图。您可以参考以下查询,如果此解决方法对您有帮助,请告诉我:

    创建视图:

    CREATE OR REPLACE VIEW dataset2.view3 AS
    select *, ROW_NUMBER() over (
    partition by id
    order by id, ts
    ) as rownum from `myproject.dataset2.part4` where ts > TIMESTAMP("2021-09-05 08:30:00")
    
    

    在视图中与 ROW_NUMBER() 一起,我在查询中添加了 Where 子句。

    查询:

    Select * from `myproject.dataset2.view3`
    

    输出:

    如果您在查询视图时添加另一个 where 子句,它将起作用并且不会抛出任何错误。

    查询:

    SELECT * FROM `myproject.dataset2.view3` where ts > TIMESTAMP("2021-10-30 10:20:02")
    

    输出:

    根据您的回复,由于您无法限制通过视图显示的真实数据时间范围,您可以参考以下案例:

    案例 1(按 id 分区):

    CREATE OR REPLACE VIEW dataset2.view8 AS
    select *, ROW_NUMBER() over (
    partition by id
    order by id,ts
    ) as rownum from `myproject.dataset2.part4` where ts IS NOT NULL
    
    

    查询 1(在视图上):

    SELECT * FROM `myprojectproject.dataset2.view8`
    

    它处理了 160B 的数据。

    查询 2(在视图上):

    SELECT * FROM `myproject.dataset2.view 8` where ts > TIMESTAMP("2021-09-05 08:30:00")
    

    它还处理了 160B 的数据,这意味着如果您按 id 进行分区,则不会发生分区修剪。

    案例 2(按 ts 分区):

    CREATE OR REPLACE VIEW dataset2.view8 AS
    select *, ROW_NUMBER() over (
    partition by ts
    order by id,ts
    ) as rownum from `myproject.dataset2.part4` where ts IS NOT NULL
    

    Query1(在视图上):

    SELECT * FROM `myproject.dataset2.view 8`
    

    它处理了 160B 的数据。

    Query2(在视图上):

    SELECT * FROM `myproject.dataset2.view 8` where ts > TIMESTAMP("2021-09-05 08:30:00")
    

    返回 128B 的数据,表示通过 ts 分区进行分区剪枝。

    由于您的要求是实现分区修剪,因此我尝试了按 ts 分区,因为在创建视图后,您将查询视图而不是表。因此,要实现分区修剪,请尝试在创建视图时使用相同的分区条件,即 按 ts 分区,您可以在查询视图时使用 WHERE 子句。 p>

    如果这不能满足您的要求,请为您的示例数据提供输出,并说明您为什么要在视图中按 id 分区的用例。

    【讨论】:

    • 谢谢桑迪普。我们还尝试在视图创建中添加“位置”。但是,对于我们的案例,我们不能限制通过视图暴露的真实数据时间范围,用户希望能够从视图中查询所有数据。这意味着我们只能过滤具有始终为真条件的 TS,例如“TS 不为空”或“TS > TIMESTAMP("1970-01-01 00:00:00")。”通过这样做,视图查询不会抛出错误,但它的性能很差,因为在执行查询时实际上没有分区修剪,即使我们在视图查询时添加了额外的 TS 过滤器。
    • 嗨@fishfish311,我已经更新了答案。
    猜你喜欢
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 2012-06-19
    • 2018-03-30
    • 2013-01-06
    • 2021-08-28
    • 2020-05-31
    • 1970-01-01
    相关资源
    最近更新 更多