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 でこのアプローチを使用している場合は、NEWID()
RAND()がすべての行に対して同じ値を返す可能性があるため、T-SQL 関数を使用する必要があります。
編集:5年後
より大きなテーブルでこの問題に再び遭遇し、@ignorant のソリューションのバージョンを 2 つの調整で使用することになりました。
- 希望するサンプル サイズの 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()
。