[解決済み] Sqlデータベースからの単純な無作為標本
質問
SQLで効率的に単純な無作為抽出を行うには?問題のデータベースはMySQLを使用しています。私のテーブルは少なくとも20万行で、約1万件の単純無作為抽出をしたいのです。
答えは、quot;learn" です。
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()
は、すべての行に対して同じ値を返す可能性があります。
.
edit: 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()
また
解決方法は?
この種の問題については、こちらで非常に興味深い議論が展開されています。 http://www.titov.net/2005/09/21/do-not-use-order-by-rand-or-how-to-get-random-rows-from-table/
テーブルに関する仮定が全くない場合、O(n lg n)のソリューションがベストだと思います。 というのも、必ずしも大きな配列全体をソートする必要はなく、最小の m 回を検索すればよいからです。 しかし、あなたが投稿したような数の場合、mはとにかくlg nより大きいです。
試してみたい3つの前提条件
-
テーブルには、ユニークでインデックス付きの主キーが存在します。
-
選択したいランダムな行の数 (m) は、テーブルの行の数 (n) よりもはるかに小さい。
-
一意な主キーは1からnまでの隙間のない整数である。
仮定1と2だけならO(n)でできると思います。ただし、仮定3に合わせてテーブルにインデックスを全部書く必要があるので、必ずしも高速なO(n)とは言えません。 もし、テーブルについて何か他の良い仮定が追加的にできれば、このタスクはO(m log m)で実行可能です。 仮定3は、作業しやすい素敵な追加特性でしょう。 m個の数字を連続して生成するときに重複がないことを保証する乱数生成器があれば、O(m)の解決策が可能になります。
3つの前提条件を考えると、1〜nの間でm個のユニークな乱数を生成し、そのキーを持つ行をテーブルから選択するのが基本的な考え方です。 今、目の前にmysqlとかないので、ちょっと擬似コードで書くとこんな感じになります。
create table RandomKeys (RandomKey int)
create table RandomKeysAttempt (RandomKey int)
-- generate m random keys between 1 and n
for i = 1 to m
insert RandomKeysAttempt select rand()*n + 1
-- eliminate duplicates
insert RandomKeys select distinct RandomKey from RandomKeysAttempt
-- as long as we don't have enough, keep generating new keys,
-- with luck (and m much less than n), this won't be necessary
while count(RandomKeys) < m
NextAttempt = rand()*n + 1
if not exists (select * from RandomKeys where RandomKey = NextAttempt)
insert RandomKeys select NextAttempt
-- get our random rows
select *
from RandomKeys r
join table t ON r.RandomKey = t.UniqueKey
もし本当に効率を重視するのであれば、ある種の手続き型言語でランダムキー生成を行い、その結果をデータベースに挿入することを検討してもよいでしょう。
関連
-
[解決済み] WHEREで集計関数は使用できません "というエラーを回避する方法
-
[解決済み] エラー 2005 (hy000)。Google Cloud SQL クライアントの MySQL サーバーホスト '[35.232.51.216]' (0) が不明です。
-
[解決済み] SQL ServerでSELECTからUPDATEする方法とは?
-
[解決済み] PHPでSQLインジェクションを防ぐにはどうしたらいいですか?
-
[解決済み] MySQLでコマンドラインを使用してSQLファイルをインポートするにはどうすればよいですか?
-
[解決済み] JavaScriptでランダムな文字列/文字を生成する
-
[解決済み] JavaScriptで特定の範囲のランダムな整数を生成する?
-
[解決済み] 乱数(int)を生成する方法を教えてください。
-
[解決済み] JavaScriptで2つの数値の間の乱数を生成する
-
[解決済み] SQL Server テーブルからランダムな n 行を選択する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】mysql 外部キー制約が不正に形成されているエラー
-
[解決済み】SQL文が動作しない-「オペランド型の衝突:dateはintと互換性がない」。
-
[解決済み】MySQL 派生テーブルはすべて独自のエイリアスを持つ必要があります。
-
[解決済み】MySQLのDESCRIBE [table]に相当するSQLiteはあるか?]
-
[解決済み] MySQLで「一意のテーブル/エイリアスでない」場合
-
[解決済み] Mysql: const テーブルを読み込んだ後、不可能な場所に気づいた。
-
[解決済み] MySQLのカラムを並べ替えるには?
-
[解決済み] mysql サーバーがクラッシュした -mysqld got signal 6
-
[解決済み] MySQLで "no "キーワードは何に使うのですか?
-
[解決済み] エラー 2005 (hy000)。Google Cloud SQL クライアントの MySQL サーバーホスト '[35.232.51.216]' (0) が不明です。