mysql の RAND() のランダム クエリ レコードに対する効率の問題と解決策

WBOY
リリース: 2016-07-25 09:03:43
オリジナル
1159 人が閲覧しました
  1. #指定範囲のデータテーブルを作成する

  2. #auther: Xiaoqiang
  3. #date: 2008-03-31
  4. テーブルrandnumberを作成する
  5. 数値として-1を選択する
  6. union
  7. select -2
  8. union
  9. 選択-3
  10. ユニオン
  11. 選択-4
  12. ユニオン
  13. 選択-5
  14. ユニオン
  15. 選択0
  16. ユニオン
  17. 選択1
  18. ユニオン
  19. 選択2
  20. ユニオン
  21. 選択3
  22. ユニオン
  23. 選択4
  24. ユニオン
  25. 選択5 < ;p>#乱数を取得します
  26. #作成者: Xiaoqiang (占い師)
  27. #日付: 2008-03-31
  28. randnumber から数値を選択
  29. rand() 制限 1 で注文

コードをコピー

利点: 乱数はデータの特定の部分を指定でき、連続している必要はありません。 短所: 乱数の範囲が非常に広い場合、テーブルの作成がより困難になります。

2. MySQL の ROUND() と RAND() 関数を使用して実装します

  1. #SQL ステートメント 1 つで実行できます
  2. SELECT ROUND((0.5-RAND())*2*5)
  3. #注意
  4. #0.5-rand() は -0.5 から +0.5 までの乱数を取得できます
  5. #( 0.5-rand())*2 は -1 から +1 までの乱数を取得できます
  6. #(0.5-rand())*2*5 は -5 から +5 までの乱数を取得できます
  7. #ROUND((0.5- RAND( ))*2*5) は、-5 から +5 までのランダムな整数を取得できます
コードをコピー

しかし、その後、MYSQL の公式マニュアルを確認したところ、その中にある RAND() のヒントは、おそらく次のことを意味します。 ORDER 内 RAND() 関数は、データ列が複数回スキャンされるため、BY 句では使用できません。ただし、MYSQL 3.23 バージョンでも、ORDER BY RAND() を使用してランダム化を実現できます。 しかし、実際にテストしてみると、これは非常に非効率であることがわかりました。 150,000 項目を超えるデータベースでは、5 つのデータをクエリするのに 8 秒以上かかります。公式マニュアルを見ると、ORDER BY句に配置したrand()が複数回実行されると書かれており、当然ながら非常に非効率的です。

インターネットでは、基本的に max(id) * rand() をクエリしてデータをランダムに取得します。

  1. SELECT * FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * (SELECT MAX(id) FROM `table`)) AS id) AS t2 WHERE t1.id >= t2.id ORDER BY t1.id ASC LIMIT 5;
コードをコピー

ただし、これにより 5 つの連続レコードが生成されます。解決策は、一度に 1 つのクエリを 5 回実行することだけです。それでも、150,000 のエントリを含むテーブルのクエリにかかる時間はわずか 0.01 秒未満であるため、それだけの価値があります。 次のステートメントでは、mysql フォーラムで誰かが使用している JOIN を使用しています。

  1. SELECT * FROM `table` WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` ) ORDER BY id LIMIT 1;
コードをコピー

meテストしてみると、所要時間は 0.5 秒で、速度は良好ですが、上記の記述とはまだ大きなギャップがあります。いつも何かが普通ではないように感じます。 そこで文を書き直しました。

  1. SELECT * FROM `table`
  2. WHERE id >= (SELECT Floor(RAND() * (SELECT MAX(id) FROM `table`)))
  3. ORDER BY id LIMIT 1;
コピーコード

これで、効率が再び向上し、クエリ時間はわずか 0.01 秒になりました 最後にステートメントを改良し、MIN(id) の判定を追加します。最初にテストしたとき、MIN(id) 判定を追加しなかったため、テーブルの最初の数行が常に半分の時間でクエリされていました。 完全なクエリ ステートメント:

  1. SELECT * FROM `table`
  2. WHERE id >= (SELECT Floor( RAND() * ((SELECT MAX(id) FROM `table`)-(SELECT MIN(id) FROM `table`) ) + (SELECT MIN(id) FROM `table`)))
  3. ORDER BY id LIMIT 1;
  4. SELECT *
  5. FROM `table` AS t1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM ` table`)-(SELECT MIN(id) FROM `table`))+(SELECT MIN(id) FROM `table`)) AS id) AS t2
  6. WHERE t1.id >= t2.id
  7. ORDER BY t1。 id LIMIT 1;
コードをコピー

最後に、PHP でこれら 2 つのステートメントを 10 回クエリします。 前者には 0.147433 秒かかります 後者には 0.015130 秒かかります JOIN 構文を使用する方が、WHERE で関数を直接使用するよりもはるかに効率的であるようです。 多くのテストを行った結果、結合構文を直接使用するよりも、より優れた提出物を持った友人が集まって他のユーザーとチャットできることがわかりました。



ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート