3

データが変更されていないテーブルからランダムな行を取得しようとしています。大規模なデータセットにはひどく、拡張性が良くないORDER BY RAND()を試してみる人がいることを読みました。

また、SQLで最小/最大範囲のランダムな行を取得するという解決策も見てきました:FLOOR(MAX(needed_id)* RAND)しかし、これは行が連続している場合にのみ機能します:1,2、 3,4,5,6,7,8,9,10。

引き出す必要のあるデータはシーケンシャルではありません。例:1、2、3、4、10、11、12、13

だから私は2つの解決策があると思っています:

最初の解決策: これを実行し続けます:FLOOR(MAX(needed_id)* RAND)正しいタイプの行を受け取るまで(1/6の確率)

2番目の解決策:次 のように(データが変更されないため)複製テーブルを作成します。

temp_id | needed_id | type 
1            1          1
2            4          1
3            7          2
3            8          2

したがって、次のメソッドを使用してランダムなtemp_idを引き出すことができます。FLOOR(MAX(temp_id)* RAND)-WHERE type = 1

どう思いますか?正しい行を受け取るまで、最初のソリューションを約6回実行する可能性がありますが、2番目のソリューションではすぐに機能しますが、別のテーブルが必要です。

4

3 に答える 3

4

あなたの声明

ただし、これは行が連続している場合にのみ機能します。

完全に正しくありません:floor()とのmax()例は、次のような何かを行うため、非連続行で機能します

WHERE id >= FLOOR(RAND()*MAX(id)) LIMIT 1

したがって、取得しているランダムヒットに最も近いIDを取得します。

これは、シーケンスの大きなギャップの直後にあるヒットをわずかに優先しますが、データセットによってはそれほど悪くない場合があります。

したがって、このわずかな設定で発生する問題の量、データセットの状態などによっては、これが最善の解決策になる可能性があります。

一部の人には不明なため、関数の使用法は問題ではありません。

MAXインデックス付きフィールドでは高速です。すべての行をカウントする必要はありません(innoDBでは低速です)。BTREEインデックスをトラバースするだけでよいので、この値をlog時間内に見つけることができます。これはほぼ瞬時です

FLOOR線形時間で実行される単なる数学関数です。と同じようにRANDORDER BY rand()のせいで遅くはないがrand、テーブル全体を注文する必要があるので気をつけてください!これはランドの問題ではなく、秩序の問題です。

これで、次のようなクエリが作成されました。

WHERE id >= 48 LIMIT 1

もちろん、これはインデックス付きフィールドでは非常に高速です。48なんらかのテーブルスキャンを実行することによってではなく、それ(例)を取得したことを忘れないでください。

于 2011-06-19T11:31:49.143 に答える
1

$cnt=行数。この値はキャッシュできます(InnoDBを使用する場合は非常に推奨されます)。

$rnd = mt_rand(0,$cnt);

クエリ:

SELECT * FROM `table` WHERE `where_cond`='some_value' LIMIT $rnd,1

もちろん、任意のwhere句を使用して任意の値を選択できます。すべてのトリックはLIMIT $ rnd、1パートです。
ここには何もないので、私はこの方法が好きJOINです。
また、このメソッドは、IDがなくても、シーケンスされた行とシーケンスされていない行で使用できます。

于 2011-06-19T11:09:09.940 に答える
1

JanKneschkeの次のブログ投稿を読む必要があります。ORDERBYRAND ()

彼はいくつかの可能な解決策とそれらのパフォーマンスの振る舞いをリストします。

于 2011-06-19T11:20:53.277 に答える