我有一个大小为N的大型数据集,并希望得到一个大小为n的(统一)随机样本。 This question提供了两种可能的解决方案:
SELECT foo FROM mytable WHERE RAND() < n/N
→这很快,但不能给我正好n行(只是大约)。
SELECT foo, RAND() as r FROM mytable ORDER BY r LIMIT n
→这需要对N行进行排序,这似乎是不必要和浪费的(特别是如果n&lt;&lt; N)。
是否有结合两者优势的解决方案?我想我可以使用第一个解决方案来选择2n行,然后对这个较小的数据集进行排序,但它有点难看并且不能保证工作,所以我想知道是否有更好的选择。
答案 0 :(得分:4)
我使用BigQuery标准SQL和natality
样本数据集(137,826,763行)比较了两个查询的执行时间,并获得了大小为 n 的source_year
列的样本。在不使用缓存结果的情况下执行查询。
查询1:
SELECT source_year
FROM `bigquery-public-data.samples.natality`
WHERE RAND() < n/137826763
QUERY2:
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&lt; = 10 5 ,差异为 ~1s , n&gt; = 10 6 执行时间差别很大。原因似乎是当LIMIT被添加到查询中时,ORDER BY会在多个worker上运行。查看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&lt; = 10 6 ,此情况下的执行时间在&lt; = 1.5s 中有所不同。在子查询中选择 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
因此,取决于您想要样本的随机性,这可能是更好的解决方案。