0

MySQL バージョン 5.5.8 を使用しています。

次のようなテーブル、エントリ、構造があるとしましょう。

entry_id int PK
member_id FK

メンバーごとに複数のエントリが存在する可能性があります。無作為に 10 個を取得したいのですが、メンバーのエントリ数に応じて選択される可能性が高くなるように取得する必要があります。私は次のようなことができることを知っています:

SELECT member_id
FROM entries
GROUP BY member_id
ORDER BY RAND()
LIMIT 10 

しかし、それが私が望むことをするかどうかはわかりません。MySQL はレコードをグループ化し、10 を選択しますか? もしそうなら、すべてのメンバーが同じように選ばれる可能性がありますが、それは私が望んでいることではありません. 私はいくつかのテストと検索を行いましたが、決定的な答えを見つけることができません。これが私が望むことをするのか、それとも別の方法で行う必要があるのか​​ 誰かが知っていますか? どんな助けでも大歓迎です。どうもありがとう!

4

1 に答える 1

1

LIMIT 10(この場合) ランダムな順序で 10 レコード ベースを選択します。これは確かにグループ化の後です。

多分あなたはできORDER BY RAND() / count(*)ます。こうすることで、より多くの質問を持つユーザーの数が少なくなる可能性が高いため、上位 10 位に入る可能性が高くなります。

[編集]

ちなみに、時間の経過とともに(データが大きくなるにつれて)ORDER BY RAND()遅くなるようです。これを回避するには、いくつかの方法があります。Mediawiki (ウィキペディアの背後にあるソフトウェア) には興味深い方法があります: 各ページに対して乱数を生成するため、「ランダム ページ」を選択すると、0 から 1 の間の乱数を 1 つ生成し、その数に最も近いページを選択します。

WHERE number > {randomNumber} ORDER BY number LIMIT 1` 

これにより、クエリごとにその一時テーブルを生成する必要がなくなります。データが大きくなった場合は定期的に数値を再生成する必要があり、数値が均等に生成されるようにする必要があります。これは簡単です。新しいレコードの場合は、乱数を生成するだけです。リスト全体が定期的に更新されます。すべてのレコードが照会されます。次に、その順序の各レコードには 0 から 1 の間の番号が割り当てられますが、増加する番号で、それは増加します1 / recordCount。そうすれば、レコードは等間隔に配置され、それらを見つけることの変化はそれぞれのレコードで同じになります。

その方法も使えます。長期的にはクエリが高速になり、ディストリビューションをよりスマートにすることができます: 1) 「memberCount」を使用する代わりに、「totalEntryCount」を使用できます。2) でインクリメントする代わりに1 / 'memberCount'、 を使用できますentryCountForMember / totalEntryCount。そうすれば、より多くのエントリを持つメンバーの前のギャップが大きくなるため、乱数に一致する可能性も大きくなります。たとえば、メンバーは次のようになります。

name  entries   number  delta
bob        10     0.1    0.10
john        1     0.11   0.01
jim         5     0.16   0.05
fred       84     1      0.84

もちろん、デルタは保存されませんが、追加された数値が表示されます。Mediawiki の例では、このデルタは各ページで同じですが、あなたの場合はエントリ数に依存する可能性があります。ご覧のとおり、bob と john の間にはわずかなギャップしかないため、0 と bob の間の乱数を選択する可能性は、bob と john の間の乱数を選択する場合の 10 倍になります。つまり、ボブを選ぶ確率は、ジョンを選ぶ確率の 10 倍です。

数値を定期的に再配布する (cron) ジョブが必要になります。これは、変更のたびに再配布したくないためですが、扱っているデータの種類については、リアルタイムである必要はありません。多くのメンバーと多くのエントリを取得すると、クエリが大幅に高速化されます。

于 2012-09-29T22:25:42.410 に答える