2011-08-02 3 views
2

私はORDER BY RAND()とそのパフォーマンスの問題について読んだことがあります。これらは大きなデータセットを返すクエリにのみ適用されますか?たとえば、100,000行のテーブルがあり、WHERE句を使用して10個のレコードを含むデータセットを返し、ORDER BY RAND()LIMIT 1を使用すると、テーブルがフィルタリングされた後にこのORDER BY RAND()が適用されます。 WHERE句に一致するレコードがあるため、パフォーマンス上の問題はごくわずかです。MySQL ORDER BY RAND()はいつ機能しますか?

+0

事実上何でもすぐに行くことができますが、概念的にLIMITはORDER BY句の後に適用されます。つまり、クエリオプティマイザによって異なります。なぜテストDBで試してみませんか? –

+0

以下の私の実験を参照してください。 - ORDER BY RAND()はWHERE句で返されたレコードのサブセットに適用されます - 143レコードを返すレコードセットの場合、ランダムレコードに制限すると、 where句を持たないテーブル全体にはかなり時間がかかりました。 – key2starz

答えて

8

そうだね、それが持つ行の数、GROUP BYを減らし、およびHAVINGの後、ORDER BYを適用します。ただし、LIMITの前にORDER BYを適用します。

したがって、十分な数の行をフィルタリングすると、ORDER BY RAND()はパフォーマンスに大きな影響を与えることなく、目的の値を達成できます。シンプルで読みやすいコードには正当な利益があります。

あなたのクエリでは、行が何か小さいものになるはずですが、データが大きくなるにつれて、並べ替える必要がある行の数が再び大きくなるという問題が発生します。あなたのクエリは、並べ替えられた結果のLIMIT 10は、500k行でORDER BY RAND()を実行しているという事実を隠しています。あなたは不思議なほどパフォーマンスが悪化しているのを見ているだけです。

私は私の本SQL Antipatterns: Avoiding the Pitfalls of Database Programmingで、またはスタックオーバーフロー上、ここで他の回答にランダムな行を取り出すための代替方法について書かれています:

+0

あなたの答えと矛盾する2つの他のポスターは、WHERE句に関係なくテーブルのすべての行に対して常に乱数を生成します。私自身のテストに基づいて、あなたの答えは正解でした。ありがとう!私の場合は、データベーステーブルの小さなサブセットからランダムな行が必要です。 – key2starz

+0

Bill、これを読んだら、2つのクエリのテクニックについてここで読んでいます:http://stackoverflow.com/questions/3558665/randomizing-large-dataset/3558919#3558919私の場合、複数のクエリを使用する必要がありますジョインなどがあります。このテクニックはその場合も機能しますか? – key2starz

0

RAND()の値は各行ごとに計算されるため、大きなデータセットの場合はそれほど効率的ではありません。LIMIT句はそれを変更しません。この問題を回避する一般的な方法は、あらかじめ乱数を計算し、あらかじめ生成されたインデックス付きの列に基づいてそれに対応する行を取得することです。あなたが選択する行数は問題ではありません

http://jan.kneschke.de/projects/mysql/order-by-rand/

2

は、ここに1つの詳細な説明です。 ORDER BY RAND()の場合、テーブル内のすべての単一の行に対して乱数が計算されます。これは、どの行が最大値を生成したのかを知るためには、各行のランダム値を計算する必要があるからです。したがって、100,000行のテーブルがあり、ORDER BY RAND() LIMIT 1を呼び出すと、100,000行の乱数を生成し、その数でソートしてから最初のものを与えるようにMySQLに指示します。

  1. SELECT COUNT(*)Table

  2. からあなたのスクリプト/プログラミング言語で0と上記のクエリの結果マイナス1の間の乱数を生成します:それははるかに高速にある

    Table LIMITのrandom_number_here FROM

  3. SELECT *、1

1

をクイックテストに基づいて、ORDER BY RAND()が適用されるのはの後に WHEREステートメントが適用され、データセット全体に適用されるわけではありません。 50,000行を持つ表から

結果:わずかなデータセットを扱う場合

SELECT * FROM `mytable` LIMIT 1 (1 total, Query took 0.0007 sec) 
SELECT * FROM `mytable` WHERE First = 'Hilda' LIMIT 1 (1 total, Query took 0.0010 sec) 
SELECT * FROM `mytable` WHERE First = 'Hilda' (142 total, Query took 0.0201 sec) 
SELECT * FROM `mytable` WHERE First = 'Hilda' ORDER BY RAND() LIMIT 1 (1 total, Query took 0.0229 sec) 
SELECT * FROM `mytable` WHERE First = 'Hilda' ORDER BY RAND() (142 total, Query took 0.0236 sec) 
SELECT * FROM `mytable` ORDER BY RAND() LIMIT 1 (1 total, Query took 0.4224 sec) 
関連する問題