表采样
利用表采样,您可以查询大型 BigQuery 表中的数据子集。采样会返回各种记录,同时避免了与扫描和处理整个表相关的费用。
使用表采样
如需在查询中使用表采样,请添加 TABLESAMPLE
子句。例如,以下查询选择表大约 10% 的表数据:
SELECT * FROM dataset.my_table TABLESAMPLE SYSTEM (10 PERCENT)
与 LIMIT
子句不同,TABLESAMPLE
从表中随机返回数据子集。此外,BigQuery 不会缓存包含 TABLESAMPLE
子句的查询的结果,因此查询可能每次返回不同的结果。
您可将 TABLESAMPLE
子句与其他选择条件结合使用。以下示例演示了表的 50% 示例,然后应用 WHERE
子句:
SELECT *
FROM dataset.my_table TABLESAMPLE SYSTEM (50 PERCENT)
WHERE customer_id = 1
下一个示例将 TABLESAMPLE
子句与 JOIN
子句组合:
SELECT *
FROM dataset.table1 T1 TABLESAMPLE SYSTEM (10 PERCENT)
JOIN dataset.table2 T2 TABLESAMPLE SYSTEM (20 PERCENT) USING (customer_id)
对于较小的表,如果联接两个样本且所有采样行都不符合联接条件,则您可能会收到空结果。
您可以将百分比指定为查询参数。以下示例展示了如何使用 bq 命令行工具将百分比传递给查询:
bq query --use_legacy_sql=false --parameter=percent:INT64:29 \
'SELECT * FROM `dataset.my_table` TABLESAMPLE SYSTEM (@percent PERCENT)`
BigQuery 表整理成数据块。TABLESAMPLE
子句的工作原理:从表中随机选择一定百分比的数据块,并读取所选块中的所有行。采样粒度受数据块数量的限制。
如果表或表分区的大小超过 1 GB,则 BigQuery 通常会将表或表分区拆分为多个块。较小的表可能包含单个数据块。在这种情况下,TABLESAMPLE
子句读取整个表。如果采样百分比大于零,且表不为空,则表采样始终会返回一些结果。
块的大小可能不同,因此采样行的确切比例可能有所不同。如果要对个别行而不是数据块进行采样,您可以改用 WHERE rand() < K
子句。但是,此方法要求 BigQuery 扫描整个表。为了节省费用但仍从行层级采样获益,您可以结合使用这两种方法。
以下示例从存储空间中读取大约 20% 的数据块,然后随机选择这些块中的 10% 的行:
SELECT * FROM dataset.my_table TABLESAMPLE SYSTEM (20 PERCENT)
WHERE rand() < 0.1
外部表
您可以将 TABLESAMPLE
子句与将数据存储在文件集中的外部表搭配使用。BigQuery 会对表引用的外部文件的子集进行采样。对于某些文件格式,BigQuery 可以将各个文件拆分为块以进行采样。一些外部数据(例如 Google 表格中的数据)只包含作为一个数据块采样的单个文件。
从写入优化的存储空间进行采样
如果您将表采样与流式插入功能搭配使用,则 BigQuery 会对写入优化的存储空间中的数据进行采样。在某些情况下,写入优化的存储空间中的所有数据会表示为单个块。发生这种情况时,写入优化的存储空间中的所有数据要么都显示在结果中,要么全部都不显示。
分区表和聚簇表
分区和聚簇会生成块,其中特定块中的所有行具有相同的分区键或具有闭合值的聚簇属性。因此,与非分区表、非聚簇表的样本集相比,这些表的样本集更容易出现偏差。
限制
- 采样表只能在查询语句中出现一次。此限制包括视图定义中引用的表。
- 不支持从视图采样数据。
- 不支持对子查询或表值函数调用的结果进行采样。
- 不支持从数组扫描(例如调用
UNNEST
运算符的结果)中进行抽样。 - 不支持在
IN
子查询中进行采样。 - 不支持从应用了行级安全性的表进行采样。
表采样价格
如果使用按需结算,则需要为读取的采样数据付费。BigQuery 不会缓存包含 TABLESAMPLE
子句的查询的结果,因此每次执行都会从存储空间中读取数据。