如何在 SQL 中获取有效的简单随机样本?有问题的数据库正在运行 MySQL;我的表至少有 200,000 行,我想要一个大约 10,000 的简单随机样本。
“明显”的答案是:
SELECT * FROM table ORDER BY RAND() LIMIT 10000
对于大表来说,这太慢了:它调用RAND()
每一行(已经把它放在 O(n) 处),并对它们进行排序,充其量是 O(n lg n)。有没有办法比 O(n) 更快地做到这一点?
注意:正如 Andrew Mao 在评论中指出的那样,如果您在 SQL Server 上使用这种方法,您应该使用 T-SQL 函数NEWID()
,因为 RAND()可能为所有行返回相同的值。
编辑:5年后
我在一张更大的桌子上再次遇到了这个问题,最后使用了@ignorant 解决方案的一个版本,有两个调整:
- 将行采样到我想要的样本大小的 2-5 倍,成本低廉
ORDER BY RAND()
- 在每次插入/更新时将结果保存
RAND()
到索引列。(如果您的数据集不是很频繁更新,您可能需要找到另一种方法来保持此列的新鲜度。)
为了对包含 1000 个项目的表进行抽样,我计算行数并将结果抽样到平均 10,000 行的 freeze_rand 列:
SELECT COUNT(*) FROM table; -- Use this to determine rand_low and rand_high
SELECT *
FROM table
WHERE frozen_rand BETWEEN %(rand_low)s AND %(rand_high)s
ORDER BY RAND() LIMIT 1000
(我的实际实现涉及更多工作以确保我不会欠采样,并手动包装 rand_high,但基本思想是“将 N 随机减少到几千。”)
虽然这会做出一些牺牲,但它允许我使用索引扫描对数据库进行采样,直到它再次小到可以ORDER BY RAND()
再次使用。