我将使用 BigQuery 标准 SQL 的两个查询执行时间与 natality 示例数据集(137,826,763 行)进行了比较,并获取了大小为 n 的 source_year 列的示例。执行查询时不使用缓存结果。
查询1:
SELECT source_year
FROM `bigquery-public-data.samples.natality`
WHERE RAND() < n/137826763
查询2:
SELECT source_year, rand() AS r
FROM `bigquery-public-data.samples.natality`
ORDER BY r
LIMIT n
结果:
n Query1 Query2
1000 ~2.5s ~2.5s
10000 ~3s ~3s
100000 ~3s ~4s
1000000 ~4.5s ~15s
对于 n 5 的区别是 ~1s 而对于 n >= 106 sup> 执行时间差别很大。原因似乎是当 LIMIT 添加到查询时,ORDER BY 在多个工作人员上运行。请参阅 Mikhail Berlyant 提供的原始 answer。
我认为您提议将这两个查询结合起来可能是一个可能的解决方案。因此我比较了组合查询的执行时间:
新查询:
SELECT source_year,rand() AS r
FROM (
SELECT source_year
FROM `bigquery-public-data.samples.natality`
WHERE RAND() < 2*n/137826763)
ORDER BY r
LIMIT n
结果:
n Query1 New Query
1000 ~2.5s ~3s
10000 ~3s ~3s
100000 ~3s ~3s
1000000 ~4.5s ~6s
对于 n 6,这种情况下的执行时间在 内变化。最好在子查询中选择 n+some_rows 行而不是 2n 行,其中 some_rows 是一个足够大的常数,可以得到超过 n 行。
关于您所说的“不保证有效”,我了解您担心新查询无法准确检索 n 行。在这种情况下,如果 some_rows 足够大,它在子查询中总是会得到多于 n 行。因此,查询将准确返回 n 行。
总而言之,组合查询不如 Query1 快,但它准确地得到 n 行,并且比 Query2 快。因此,它可能是均匀随机样本的解决方案。我想指出,如果未指定 ORDER BY,BigQuery 输出是不确定的,这意味着您每次执行查询时可能会收到不同的结果。如果您尝试在不使用缓存结果的情况下多次执行以下查询,您将得到不同的结果。
SELECT *
FROM `bigquery-samples.wikipedia_benchmark.Wiki1B`
LIMIT 5
因此,取决于您希望获得样本的随机程度,这可能是一个更好的解决方案。