表采样

利用表采样,您可以查询大型 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 子句的查询的结果,因此每次执行都会从存储空间中读取数据。