持续具体化视图查询
如需创建 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 查询中,您可以使用以下聚合函数:
COUNTSUMMINMAXHLL_COUNT.INITHLL_COUNT.MERGEHLL_COUNT.MERGE_PARTIALANY_VALUEBIT_ANDBIT_ORBIT_XORAVG
如果您使用 SELECT COUNT(*),则必须定义行键,如以下示例所示:
SELECT
'*' AS _key,
COUNT(*) AS count
FROM
foo
GROUP BY
_key;
不支持的 SQL 功能
您无法使用以下 SQL 功能:
- GoogleSQL for Bigtable 不支持的任何功能
ARRAYARRAY_AGGARRAY_CONCAT_AGGCOUNT_IFCURRENT_TIME和大多数其他非确定性函数,但有例外情况。DATE、DATETIME作为输出列(使用TIMESTAMP或存储字符串)。DESC输出中的排序DISTINCT选项,如SUM(*DISTINCT* value)中所示)LIMIT/OFFSETSELECT *OVER子句,用于创建窗口聚合STRUCT
您也无法嵌套 GROUP BY 或 ORDER BY 子句,也无法创建地图列。如需了解其他限制,请参阅限制。
避免排除的行
在以下情况下,输入行会被排除在连续的具体化视图之外:
- 从行中选择的数据超过 1 MiB。例如,如果您的查询是
SELECT apple AS apples , SUM(banana) AS sum_bananas FROM my_table GROUP BY apples,则apple和banana列中包含超过 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 BY 或 ORDER 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 ASC、b ASC、c 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 一致) |