行数が少ないテーブル (トップ 50) があります。テーブルからランダムな値を取得する必要があります
ORDER BY RAND() LIMIT 1
。rand はどのように計算されますか? (idk、5秒ごと)。
3 に答える
MySQL 疑似乱数ジェネレーターは完全に決定論的です。ドキュメントは言う:
RAND() は、完全なランダム ジェネレーターを意図したものではありません。これは、同じ MySQL バージョンのプラットフォーム間で移植可能な乱数をオンデマンドで生成する高速な方法です。
MySQL はさまざまなオペレーティング システムで動作するように設計されているため、/dev/random を使用することはできません。
MySQL は、サーバーの起動時に、 によって返される整数を使用してデフォルトのシードを初期化しますtime(0)
。ソース行に興味がある場合は、ファイル sql/mysqld.cc, function の MySQL ソースにありますinit_server_components()
。それ自体が再シードされることはないと思います。
その後の「乱数」は、シードのみに基づいています。ソース ファイル mysys_ssl/my_rnd.cc の function を参照してくださいmy_rnd()
。
ランダム化のパフォーマンスと品質の両方に関するランダム選択タスクのベスト プラクティス ソリューションは、最小主キー値と最大主キー値の間のランダム値を生成することです。次に、そのランダムな値を使用して、テーブルの主キーを選択します。
SELECT ... FROM MyTable WHERE id > $random LIMIT 1
= の代わりに > を使用する理由は、行が削除またはロールバックされたために id にギャップがある可能性があるか、条件に一致する行間にギャップがあるように WHERE 句に他の条件がある可能性があるためです。 .
この大なり法の欠点:
- このようなギャップに続く行は選択される可能性が高く、ギャップが大きいほどチャンスが大きくなります。
- ランダム値を生成する前に、MIN(id) と MAX(id) を知る必要があります。
- 複数のランダムな行が必要な場合はうまくいきません。
この方法の利点:
- テーブルのサイズが小さい場合でも、ORDER BY RAND() よりもはるかに高速です。
- SQL の外部でランダム関数を使用できます。
RAND は疑似乱数です。セキュリティのための使用には注意してください。「50行からランダムに1行を選択する」というのはセキュリティのためではないと思うので、おそらく問題ありません。
小さなテーブルではかなり高速です。大きなテーブルからランダムな行を選択するのは恐ろしいことです。すべての行に疑似乱数のタグを付けてから並べ替える必要があります。あなたが説明しているアプリケーションについては、@TheEwookの提案はまさに正しいです。小さなテーブルであっても、1 ミリ秒に 1 回以上の頻度でソートすると、強力な MySQL ハードウェアでさえ圧倒される可能性があります。
テストしていて、ある種の単体テスト用に繰り返し可能な乱数シーケンスが必要な場合を除き、RAND をシードしないでください。これは、推測しにくいと思っていたセッション トークンを生成したときに、難しい方法で学んだことがあります。MySQL 関係者は RAND で良い仕事をしてくれました。あなたが話しているアプリケーションについては、彼らを信頼することができます。
シードしないと、/dev/random からのランダムなシードで始まると思います (確かではありません)。
暗号グレードの乱数が必要な場合は、自分で /dev/random を読んでください。ただし、/dev/random で生成できるレートは限られていることに注意してください。/dev/urandom は /dev/random を使用してより高速なレートを生成しますが、そのエントロピー プールはそれほど高くありません。