5

私はこのテーブルを持っています、

person_id   int(10) pk
points      int(6) index
other columns not very important

10M行のテーブルで非常に高速なこのランダム関数があります:

SELECT person_id
  FROM persons AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(person_id)
                        FROM persons)) AS id)
        AS r2
 WHERE r1.person_id >= r2.id
 ORDER BY r1.person_id ASC
 LIMIT 1

これはすべて素晴らしいですが、ポイントが 0 より大きい人だけを表示したいと思います。表の例:

PERSON_ID      POINTS
1              4
2              6
3              0
4              3

where 句に追加AND points > 0すると、person_id 3 を選択できないため、ギャップが作成され、ランダムに person_id 3 を選択すると、person_id 4 が選択されます。これにより、人 4 が選ばれる可能性が高くなります。where句で動作するようにクエリを調整し、すべての行が同じ割合で選択されるようにする方法を提案しました。

情報テーブル: テーブルは均一で、person_id にギャップはありません。約 90% が 0 ポイントになります。ポイント = 0 およびポイント > 0 のクエリを作成したいと思います。

誰かが言うrand()に、これは 10 万行を超えるテーブルの解決策ではありません。

おまけの質問: 1 つのクエリで x 個のランダムな行を選択できるので、ランダムな行を増やしたいときにこのクエリを数回呼び出す必要はありませんか?

重要な注意: パフォーマンスが重要です。1,000 万行以上のクエリでは、0.0005 秒かかる現在のクエリよりもそれほど長くはかからない可能性があります。私は 0.05 秒未満にとどまることを好みます。

最後の注意: 上記の要件でクエリがこれほど高速になることはないと思われるが、別の解決策が可能である場合 (100 行をフェッチし、0 を超えるポイントを持つ x ランダムを表示するなど)、教えてください :)

あなたの助けに本当に感謝し、すべての助けを歓迎します:)

4

1 に答える 1

1

本当に処理したいレコードのインライン ギャップフリー ID を生成し、利用可能なレコードの総数を使用してランダム セレクターを生成できます。

これを試してください(row_numberジェネレーターのためにここで選択された答えへの小道具):

    SELECT r1.*
    FROM
        (SELECT  person_id,
                 @curRow := @curRow + 1 AS row_number
        FROM persons as p,
             (SELECT @curRow := 0) r0
        WHERE points>0) r1
    , (SELECT COUNT(1) * RAND() id
       FROM persons
       WHERE points>0) r2
    WHERE r1.person_id>=r2.id
    ORDER BY r1.person_id ASC
    LIMIT 1;

この sqlfiddleでそれを台無しにすることができます。

于 2013-05-22T13:53:25.110 に答える