持续具体化视图查询

如需创建 Bigtable 表的连续具体化视图,请运行定义该连续具体化视图的 SQL 查询。

本文档介绍了相关概念和模式,可帮助您准备连续的具体化视图 SQL 查询。在阅读本文档之前,您应该先熟悉连续的物化视图GoogleSQL for Bigtable

连续的物化视图使用受限 SQL 语法。以下模式展示了如何构建连续的具体化视图 SQL 查询:

SELECT
  expression AS alias [, ...]
FROM from_item
[ WHERE bool_expression ]
GROUP BY expression [, ...];

from_item:
    {
      table_name [ as_alias ]
      | field_path
      }

as_alias:
    [ AS ] alias

如果您想将持续具体化视图 SQL 查询构建为异步辅助索引,请使用 ORDER BY 子句:

SELECT
  expression AS alias [, ...]
FROM from_item
[ WHERE bool_expression ]
ORDER BY expression [, ...];

from_item:
    {
      table_name [ as_alias ]
      | field_path
      }

as_alias:
    [ AS ] alias

使用非确定性函数的 SQL 查询在语义上与其他持续具体化视图查询不同。如需了解详情,请参阅本文档的不确定性查询部分。

查询限制

用于创建持续具体化视图的 SQL 查询必须遵循以下规则:

  • 必须是 SELECT 语句。
  • 必须包含 GROUP BY 子句,或者对于异步二级索引查询,必须包含 ORDER BY 子句,但不能同时包含这两个子句。
  • 必须仅使用受支持的聚合函数。
  • 每个组可以有多个聚合。

支持的聚合

在定义持续具体化视图的 SQL 查询中,您可以使用以下聚合函数:

  • COUNT
  • SUM
  • MIN
  • MAX
  • HLL_COUNT.INIT
  • HLL_COUNT.MERGE
  • HLL_COUNT.MERGE_PARTIAL
  • ANY_VALUE
  • BIT_AND
  • BIT_OR
  • BIT_XOR
  • AVG

如果您使用 SELECT COUNT(*),则必须定义行键,如以下示例所示:

SELECT
  '*' AS _key,
  COUNT(*) AS count
FROM
  foo
GROUP BY
  _key;

不支持的 SQL 功能

您无法使用以下 SQL 功能:

  • GoogleSQL for Bigtable 不支持的任何功能
  • ARRAY
  • ARRAY_AGG
  • ARRAY_CONCAT_AGG
  • COUNT_IF
  • CURRENT_TIME 和大多数其他非确定性函数,但有例外情况
  • DATEDATETIME 作为输出列(使用 TIMESTAMP 或存储字符串)。
  • DESC 输出中的排序
  • DISTINCT 选项,如 SUM(*DISTINCT* value) 中所示)
  • LIMIT/OFFSET
  • SELECT *
  • OVER 子句,用于创建窗口聚合
  • STRUCT

您也无法嵌套 GROUP BYORDER BY 子句,也无法创建地图列。如需了解其他限制,请参阅限制

避免排除的行

在以下情况下,输入行会被排除在连续的具体化视图之外:

  • 从行中选择的数据超过 1 MiB。例如,如果您的查询是 SELECT apple AS apples , SUM(banana) AS sum_bananas FROM my_table GROUP BY apples,则 applebanana 列中包含超过 1MiB 数据的任何行都会从持续具体化视图中排除。
  • 从相应行输出的数据超过 1 MiB。当您使用 SELECT REPEAT(apple, 1000) 等查询或使用大型常量时,可能会出现这种情况。
  • 输出的数据量比所选的数据量多 10 倍以上。
  • 查询与您的数据不匹配。这包括尝试除以零、整数溢出,或预期使用并非在每个行键中都使用的行键格式。

排除的行在首次处理时会增加用户错误指标。 如需详细了解可帮助您监控持续具体化视图的指标,请参阅指标

查询详情

本部分介绍了持续具体化视图查询,以及查询该视图时结果的显示方式。源表中的数据是输入,持续具体化视图中的结果数据是输出。输出数据是汇总数据或未汇总数据(在定义的键中)。

SELECT 语句

SELECT 语句用于配置持续具体化视图中使用的列和聚合。该语句必须使用 GROUP BY 子句跨行进行聚合,或者使用 ORDER BY 子句创建异步二级索引。

不支持 SELECT *,但支持 SELECT COUNT(*)

与典型的 SELECT 语句一样,您可以针对一组分组数据进行多次聚合。未分组的列必须是汇总结果。

以下是一个标准 GROUP BY SQL 汇总查询示例:

SELECT
  myfamily["node"] AS node,
  myfamily["type"] AS type,
  COUNT(clicks) AS clicks_per_key
FROM
  mytable
GROUP BY
  node,
  type

行键和未汇总的数据

您可以指定 _key 作为持续具体化视图的行键。否则,GROUP BY 子句中的列将构成视图中的键。

_key 列定义的行键

在定义连续具体化视图时,您可以选择指定 _key 列。(这与您对 Bigtable 表执行 SQL 查询时获得的 _key不同。)如果您指定了 _key,则需遵守以下规则:

  • 您必须按 _key 分组,并且不能按任何其他内容分组,但可以(选择性地)按 _timestamp 分组。如需了解详情,请参阅时间戳
  • _key 列的类型必须为 BYTES

如果您计划使用 ReadRows 而不是 SQL 读取视图,指定 _key 会很有用,因为这样您可以控制行键格式。另一方面,对具有已定义 _key 的视图的 SQL 查询可能需要明确解码 _key,而不仅仅是返回结构化键列。

GROUP BYORDER BY 子句定义的行键

如果您未指定 _key,则 SELECT 列表中的非聚合列将成为视图中的行键。您可以为键列分配 SQL 惯例支持的任何名称。如果您打算使用 SQL 查询视图,而不是使用 ReadRows 请求,请使用此方法。

SELECT 列表中的非聚合输出列必须包含在 GROUP BY 子句中。GROUP BY 子句中写入列的顺序就是数据在连续具体化视图行键中存储的顺序。例如,GROUP BY a, b, c 隐式为 ORDER BY a ASC, b ASC, c ASC

如果您使用 ORDER BY 子句而非 GROUP BY 子句来创建异步二级索引,则 ORDER BY 子句中 SELECT 列表内的列会成为视图中的行键。在 ORDER BY 子句中写入列的顺序就是数据在连续具体化视图行键中的存储顺序。例如,ORDER BY a, b, c 会存储行键按 a ASCb ASCc ASC 排序的数据。

您的 SQL 过滤条件必须消除可能导致错误的潜在 NULL 或其他无效值。无效的行(例如包含 NULL 键列的行)会从结果中省略,并计入 materialized_view/user_errors 指标。如需调试用户错误,请尝试在持续具体化视图之外运行 SQL 查询。

汇总数据

查询中的聚合列用于定义生成持续具体化视图中数据的计算。

汇总列的别名在持续具体化视图中被视为列限定符。

请参考以下示例:

SELECT
  fam["baz"] AS baz,
  SUM(fam["foo"]) AS sum_foo,
  SUM(fam["bar"]) AS sum_bar
FROM
  TABLE

GROUP BY
  baz;

查询输出具有以下特征:

  • 每个 baz 的输出都位于单独的一行中,并按 baz ASC 顺序排列。
  • 如果给定的 baz 至少有一个 foo,则输出行的 sum_foo 为非 NULL 值。
  • 如果给定的 baz 至少有一个 bar,则输出行的 sum_bar 为非 NULL 值。
  • 如果给定的 baz 在任一列中都没有值,则会从结果中省略。

然后,如果您使用 SELECT * 查询视图,结果将类似于以下内容:

baz sum_foo sum_bar
baz1 sum_foo1 sum_bar1
baz2 sum_foo2 sum_bar2

时间戳

持续具体化视图中输出单元格的默认时间戳为 0 (1970-01-01 00:00:00Z)。当您使用 ReadRows 读取视图时,此时间戳会显示,但当您使用 SQL 查询视图时,此时间戳不会显示。

如需在输出中使用其他时间戳,您可以向查询的 SELECT 列表添加一个 TIMESTAMP 类型的列,并将其命名为 _timestamp。如果您使用 ReadRows 查询持续具体化视图,_timestamp 将成为相应行中其他单元格的时间戳。

时间戳不得为 NULL,必须大于或等于零,且必须是 1,000 的倍数(精确到毫秒)。Bigtable 不支持早于 Unix 纪元 (1970-01-01T00:00:00Z) 的单元格时间戳。

请看以下示例,该示例按天对汇总数据进行重采样。该查询使用 UNPACK 函数。

SELECT
  _key,
  TIMESTAMP_TRUNC(_timestamp, DAY) AS _timestamp,
  SUM(sum_family["sum_column"]) AS sum_column,
  SUM(sum_family["foo"]) AS second_sum_column
FROM
  UNPACK(
  SELECT
    *
  FROM
    my_table(with_history => TRUE))
GROUP BY
  1,
  2

如果给定的 SUM 在给定日期有非空输入,则输出行包含一个时间戳与截断的日期相匹配的汇总值。

如果您使用 SELECT * 查询视图,结果将类似于以下内容:

_key _timestamp sum_column second_sum_column
1 2024-05-01 00:00:00Z 23 99
2 2024-05-02 00:00:00Z 45 201
3 2024-05-03 00:00:00Z NULL 56
4 2024-05-04 00:00:00Z 8 NULL

非确定性查询

持续具体化视图支持以下非确定性 SQL 函数

集群属性函数

借助 CLUSTER_ATTRIBUTE() 函数,您可以以程序化方式访问有关运行持续具体化视图查询的 Bigtable 集群的元数据。cluster_id 属性返回处理视图的集群的字符串标识符。

将视图隔离到单个集群

为了将连续的具体化视图计算和存储隔离到单个集群(例如专用分析或报告集群),请将 CLUSTER_ATTRIBUTE('cluster_id') 与包含集群标识符的常量字符串字面量进行比较:

SELECT
  metrics['sensor_id'] AS sensor_id,
  COUNT(1) AS reading_count
FROM `TABLE_ID`
WHERE CLUSTER_ATTRIBUTE('cluster_id') = 'CLUSTER_ID'
GROUP BY 1

替换以下内容:

  • TABLE_ID:Bigtable 表的唯一标识符。
  • CLUSTER_ID:您要将视图具体化的集群的标识符。

此查询在您的实例中具有以下行为:

  • 指定集群:在与 CLUSTER_ID 匹配的集群上,WHERE 条件的评估结果为 true。Bigtable 会汇总源表中的所有数据(无论这些数据是由哪个集群提取或复制的),并将这些数据具体化到相应集群的视图副本中。
  • 其他集群:在实例中的所有其他集群上,CLUSTER_ATTRIBUTE('cluster_id') 会评估为各自的集群 ID,从而使 WHERE 条件为 false。这些集群不会计算或存储任何连续的具体化视图的行,从而节省计算和存储资源。

按聚类来源过滤数据

如果您的应用将集群元数据写入源表行(例如,写入名为 origin_cluster 的列),您可以将行的来源集群与处理集群进行匹配:

SELECT
  metrics['sensor_id'] AS sensor_id,
  COUNT(1) AS reading_count
FROM `TABLE_ID`
WHERE metrics['origin_cluster'] = CLUSTER_ATTRIBUTE('cluster_id')
GROUP BY 1

在此查询中,metrics['origin_cluster'] 是存储在行中的数据的属性,而 CLUSTER_ATTRIBUTE('cluster_id')处理视图的集群的属性。每个集群的持续具体化视图副本仅聚合存储的 origin_cluster 与相应集群的 ID 相匹配的行。

如果某些行可能未指定来源聚类,您可以使用 IF_NULL 分配后备聚类:

SELECT
  metrics['sensor_id'] AS sensor_id,
  COUNT(1) AS reading_count
FROM `TABLE_ID`
WHERE IF_NULL(metrics['origin_cluster'], 'DEFAULT_CLUSTER_ID') = CLUSTER_ATTRIBUTE('cluster_id')
GROUP BY 1

查询特征

使用 CLUSTER_ATTRIBUTE 的查询具有以下特征:

  • 由于 sensor_id 位于 GROUP BY 子句中,因此它会成为持续具体化视图中行键的一部分。
  • 如需使用此不确定性函数,您必须在创建视图时将 ignore_warnings 标志设置为 true。如需了解详情,请参阅创建持续物化视图

当您使用 SELECT * 查询视图时,结果如下所示:

sensor_id reading_count
sensor-1234 25
sensor-5678 68

限制

使用非确定性 CLUSTER_ATTRIBUTE 函数会带来严格的路由要求:

  • 不支持多集群路由:由于函数的输出取决于执行查询的物理集群,因此多集群路由会产生不确定的结果。
  • 使用单集群路由:查询使用 CLUSTER_ATTRIBUTE 的持续具体化视图时,请使用针对单集群路由配置的应用配置文件。
  • 路由到指定集群:如果您将视图隔离到特定集群(例如 WHERE CLUSTER_ATTRIBUTE('cluster_id') = 'my-reporting-cluster'),请将应用配置文件直接指向该集群。查询其他集群会返回空结果,因为视图未在其他集群上填充。

编码

如果您使用 SQL 查询连续的具体化视图,则无需了解聚合值的编码方式,因为 SQL 会将结果显示为类型化列。

如果您使用 ReadRows 从视图中读取数据,则需要在读取请求中解码汇总数据。如需详细了解 ReadRows 请求,请参阅读取

连续具体化视图中的汇总值会根据视图定义中列的输出类型,使用下表中描述的编码进行存储。

类型 编码
布尔值 1 字节值,1 = true,0 = false
BYTES 无编码
INT64(或 INT、SMALLINT、INTEGER、BIGINT、TINYINT、BYTEINT) 64 位大端序
FLOAT64 64 位 IEEE 754,不包括 NaN 和 +/-inf
STRING UTF-8
时间/时间戳 一个 64 位整数,表示自 Unix 纪元以来的微秒数(与 GoogleSQL 一致)
如需了解详情,请参阅 Data API 参考文档中的 编码

后续步骤