如何在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个项目的样本,我对数据行进行计数,并使用Frozen_rand列对结果进行平均采样,平均减少到10,000行:
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()
。
RAND()
在每个后续调用中都返回相同的值。