使用具体化视图

本文档提供有关具体化视图及其使用方式的其他信息。在阅读本文档之前,请先熟悉具体化视图简介创建具体化视图

查询具体化视图

您可以直接查询具体化视图,方式与查询常规表或标准视图相同。对具体化视图的查询始终与对视图的基表的查询一致,即使这些表自从上次具体化视图刷新以来已发生更改也不例外。 查询不会自动触发具体化刷新。

所需的角色

如需获得查询具体化视图所需的权限,请让管理员向您授予具体化视图的基表和具体化视图本身的 BigQuery Data Viewer (roles/bigquery.dataViewer) IAM 角色。 如需详细了解如何授予角色,请参阅管理访问权限

此预定义角色包含查询具体化视图所需的权限。如需查看所需的确切权限,请展开所需权限部分:

所需权限

查询具体化视图需要以下权限:

  • bigquery.tables.get
  • bigquery.tables.getData

您也可以使用自定义角色或其他预定义角色来获取这些权限。

查询需要这些权限以受益于智能调整

如需详细了解 BigQuery 中的 IAM 角色,请参阅 IAM 简介

增量更新

BigQuery 会将缓存的视图数据与新数据相结合,以提供一致的查询结果,同时仍使用具体化视图。对于单表具体化视图,如果基表自从上次刷新后未发生更改或仅添加了新数据,则可能会发生这种情况。对于 JOIN 视图,只有 JOIN 左侧的表才能附加数据。如果 JOIN 右侧的其中一个表发生更改,则无法以递增方式更新视图。

如果自上次刷新以来基表包含更新或删除内容,或者 JOIN 右侧的具体化视图的基表发生更改,则 BigQuery 会自动还原为原始查询。如需详细了解联接和具体化视图,请参阅联接。以下是可能导致更新或删除的 Google Cloud 控制台、bq 命令行工具和 API 操作示例:

  • 数据操纵语言 (DML) UPDATEMERGEDELETE 语句
  • 截断
  • 分区到期

以下元数据操作还会防止具体化视图以递增方式更新:

  • 更改分区失效日期
  • 更新或删除列

如果无法以递增方式更新具体化视图,则在查询自动或手动刷新之前,查询不会使用其缓存的数据。如需详细了解作业未使用具体化视图数据的原因,请参阅了解具体化视图受拒的原因

分区一致

如果某具体化视图已分区,则 BigQuery 会确保其分区与基表的分区列的分区一致。一致意味着来自基表的特定分区的数据对同一具体化视图有影响。例如,基表的分区 20220101 中的行仅会计入具体化视图的分区 20220101

当对具体化视图进行分区时,增量更新中描述的行为会针对每个分区进行。例如,如果删除基表的一个分区中的数据,则 BigQuery 仍然可以使用具体化视图的其他分区。

具有内联接的具体化视图只能与它们的其中一个基表一致。如果其中一个不一致基表发生更改,则会影响整个视图。

智能调整

BigQuery 会自动重写查询,以尽可能使用具体化视图。自动重写可改善查询性能和降低费用,并且不会更改查询结果。查询不会自动触发具体化刷新。如需重写查询,具体化视图必须满足以下条件:

  • 属于与其某个基表相同的数据集。
  • 使用与查询相同的基表集。
  • 包括要读取的所有列。
  • 包括要读取的所有行。

智能调整示例

请考虑以下具体化视图查询示例:

SELECT
  store_id,
  CAST(sold_datetime AS DATE) AS sold_date
  SUM(net_profit) AS sum_profit
FROM dataset.store_sales
WHERE
  CAST(sold_datetime AS DATE) >= '2021-01-01' AND
  promo_id IS NOT NULL
GROUP BY 1, 2

以下示例展示了查询,以及为什么使用此视图会或不会自动重写查询这些查询:

查询 是否重写? 原因
SELECT
SUM(net_paid) AS sum_paid,
SUM(net_profit) AS sum_profit
FROM dataset.store_sales
WHERE
CAST(sold_datetime AS DATE) >= '2021-01-01' AND
promo_id IS NOT NULL
视图必须包含要读取的所有列。视图不包含“SUM(net_Paid)”。
SELECT SUM(net_profit) AS sum_profit
FROM dataset.store_sales
WHERE
CAST(sold_datetime AS DATE) >= '2021-01-01' AND
promo_id IS NOT NULL
SELECT SUM(net_profit) AS sum_profit
FROM dataset.store_sales
WHERE
CAST(sold_datetime AS DATE) >= '2021-01-01' AND
promo_id IS NOT NULL AND
customer_id = 12345
视图必须包含要读取的所有列。视图不包含“customer”。
SELECT SUM(net_profit) AS sum_profit
FROM dataset.store_sales
WHERE
sold_datetime= '2021-01-01' AND
promo_id IS NOT NULL
视图必须包含要读取的所有列。“sell_datetime”不是输出(但“CAST(sell_datetime AS DATE)”是输出)。
SELECT SUM(net_profit) AS sum_profit
FROM dataset.store_sales
WHERE
CAST(sold_datetime AS DATE) >= '2021-01-01' AND
promo_id IS NOT NULL AND
store_id = 12345
SELECT SUM(net_profit) AS sum_profit
FROM dataset.store_sales
WHERE
CAST(sold_datetime AS DATE) >= '2021-01-01' AND
promo_id = 12345
视图必须包含要读取的所有行。“Promote_id”不是输出,因此无法将更严格的过滤条件应用于视图。
SELECT SUM(net_profit) AS sum_profit
FROM dataset.store_sales
WHERE CAST(sold_datetime AS DATE) >= '2020-01-01'
视图必须包含要读取的所有行。视图进行过滤以获得 2021 年及以后的日期,但查询读取 2020 年的日期。
SELECT SUM(net_profit) AS sum_profit
FROM dataset.store_sales
WHERE
CAST(sold_datetime AS DATE) >= '2022-01-01' AND
promo_id IS NOT NULL

了解查询是否已被重写

如需了解查询是否由智能微调重写为使用具体化视图,请检查查询计划。如果查询已被重写,则查询计划包含 READ my_materialized_view 步骤,其中 my_materialized_view 是所使用具体化视图的名称。如需了解查询不使用具体化视图的原因,请参阅了解具体化视图受拒的原因

了解具体化视图受拒的原因

查询会因为各种原因而无法使用具体化视图。了解具体化视图受拒的原因的步骤取决于您使用的查询类型:

  • 直接查询具体化视图
  • 智能调整可能选择使用具体化视图的间接查询

以下部分可帮助您了解具体化视图受拒的原因。

直接查询具体化视图

在某些情况下,具体化视图的直接查询可能不会使用缓存的数据。以下步骤可帮助您了解未使用具体化视图数据的原因:

  1. 按照监控具体化视图使用情况中的步骤操作,并在查询的 materialized_view_statistics 字段中找到目标具体化视图。
  2. 如果统计信息中存在 chosen,且其值为 TRUE,则查询会使用具体化视图。
  3. 查看 rejected_reason 字段以查找后续步骤。在大多数情况下,您可以手动刷新具体化视图,也可以等待下一次自动刷新

使用智能调整进行查询

  1. 按照监控具体化视图使用情况中的步骤操作,并在查询的 materialized_view_statistics 中找到目标具体化视图。
  2. 查看 rejected_reason 以了解后续步骤。例如,如果 rejected_reason 值为 COST,则智能调整会确定更高效的数据源来节省费用和性能。
  3. 如果具体化视图不存在,请尝试直接查询具体化视图,然后按照直接查询具体化视图中的步骤操作。
  4. 如果直接查询不使用具体化视图,则具体化视图的形状与查询不匹配。如需详细了解智能调整以及如何使用具体化视图重写查询,请参阅智能调整示例

常见问题解答

何时应使用计划查询与具体化视图?

计划查询是一种定期运行任意复杂计算的便捷方式。每次运行查询时,查询都会完全运行。系统不会使用之前的结果,您需要为查询支付全价。如果您不需要最新的数据且对数据过时有很高的容忍度,则计划查询非常有用。

具体化视图适用于需要查询最新数据,同时通过重复使用先前计算结果来减少延迟和费用的情况。您可以将具体化视图用作伪索引,加速对基表的查询,而无需更新任何现有工作流。 通过 --max_staleness 选项,您可以为具体化视图定义可接受的过时,并在处理大型频繁更改的数据集时提供始终如一的高性能和受控制的费用。

一般准则上讲,如果您未运行任意复杂的计算,请尽可能使用具体化视图。

对具体化视图进行的一些查询比对手动具体化表的相同查询慢。为什么?

通常,对具体化视图的查询并不总是等效于具体化表的查询。原因是具体化视图保证始终返回全新的结果,并且必须考虑自上次视图刷新以来在基表中添加的更改。

假设出现了这样的情景:

CREATE MATERIALIZED VIEW my_dataset.my_mv AS
SELECT date, customer_id, region, SUM(net_paid) as total_paid
FROM my_dataset.sales
GROUP BY 1, 2, 3;

CREATE TABLE my_dataset.my_materialized_table AS
SELECT date, customer_id, region, SUM(net_paid) as total_paid
FROM my_dataset.sales
GROUP BY 1, 2, 3;

例如,以下查询:

  SELECT * FROM my_dataset.my_mv LIMIT 10
通常运行速度比以下查询慢得多:
  SELECT * FROM my_dataset.my_materialized_table LIMIT 10
为了始终提供最新结果,BigQuery 必须查询基表中的新行,并将其合并到具体化视图中,然后再应用“LIMIT 10”谓词。 因此,即使具体化视图是全新的,速度仍很缓慢。

另一方面,具体化视图的聚合通常与针对具体化表的查询一样快。例如,以下方法:

  SELECT SUM(total_paid) FROM my_dataset.my_mv WHERE date > '2020-12-01'
速度如下所示:
  SELECT SUM(total_paid) FROM my_dataset.my_materialized_table WHERE date > '2020-12-01'