使用具体化视图

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

查询具体化视图

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

所需的角色

如需获得查询物化视图所需的权限,请让您的管理员为您授予物化视图的基表和物化视图本身的 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'