2

現在私は使用しています:

SELECT * 
FROM 
  table AS t1
  JOIN (
    SELECT (RAND() * (SELECT MAX(id) FROM table where column_x is null)) AS id
  ) AS t2 
WHERE 
  t1.id >= t2.id
  and column_x is null
ORDER BY t1.id ASC
LIMIT 1

これは通常非常に高速ですが、強調表示された column_x が Y (null) の条件を含めると、遅くなります。

レコードの列 X が null の場合、最も高速なランダム クエリ ソリューションは何でしょうか?

ID は PK、列 X は int(4) です。テーブルには約 100 万件のレコードが含まれており、合計サイズが 1 GB を超えており、現在 24 時間ごとに 2 倍になっています。

column_x は索引付けされています。

列 ID が連続していない可能性があります。

この場合に使用される DB エンジンは InnoDB です。

ありがとうございました。

4

4 に答える 4

3

真にランダムなレコードの取得は遅くなる可能性があります。この事実を回避することはあまりありません。真にランダムにしたい場合、クエリは、どのレコードから選択する必要があるかを知るために、関連するすべてのデータをロードする必要があります。

ただし、幸いなことに、それを行うより迅速な方法があります。それらは適切にランダムではありませんが、純粋なランダム性を速度と引き換えに満足している場合は、ほとんどの目的に十分対応できるはずです。

それを念頭に置いて、「ランダム」レコードを取得する最速の方法は、DB に追加の列を追加することです。これには、ランダムな値が取り込まれます。おそらく、主キーのソルト MD5 ハッシュでしょうか? なんでもいい。この列に適切なインデックスを追加し、その列をORDER BYクエリの句に追加するだけで、ランダムな順序でレコードが返されます。

単一のランダム レコードを取得するには、ランダム値が新しいフィールドの範囲内の値になる場所を指定LIMIT 1して追加するだけWHERE random_field > $random_valueです (たとえば、乱数の MD5 ハッシュなど)。

もちろん、ここでのマイナス面は、レコードがランダムな順序になりますが、同じランダムな順序でスタックすることです。私はそれがクエリの速度のために完璧をトレードしていると言いました. 新しい値で定期的に更新することでこれを回避できますが、最新の状態に保つ必要がある場合は問題になる可能性があると思います.

もう 1 つの欠点は、追加の列を追加することは、ストレージの制約があり、DB のサイズがすでに巨大である場合、または列を追加する前に厳密な DBA を通過させる必要がある場合、質問するには多すぎる可能性があることです。しかし、繰り返しになりますが、何かをトレードオフする必要があります。クエリの速度が必要な場合は、この追加の列が必要です。

とにかく、それが役に立ったことを願っています。

于 2012-05-20T22:47:59.510 に答える
1

explainクエリを実行しましたか? 出力は何でしたか?

: の値を保存またはキャッシュしてSELECT MAX(id) FROM table where column_x is null、それを変数として使用しないでください。クエリは次のようになります。

$rand = rand(0, $storedOrCachedMaxId);

SELECT * 
FROM 
  table AS t1
WHERE 
  t1.id >= $rand
  and column_x is null
ORDER BY t1.id ASC
LIMIT 1

より単純なクエリは、データベース上でより簡単になる可能性があります。

データに大きな穴が含まれている場合、この種のクエリでは一貫してランダムな結果が得られないことに注意してください。

于 2012-05-20T22:44:11.230 に答える
1

join も order by も limit 1 も必要ないと思います (id が一意であれば)。

SELECT *
FROM   myTable
WHERE  column_x IS NULL
   AND id = ROUND(RAND() * (SELECT MAX(Id) FROM myTable), 0)
于 2012-05-20T22:49:06.403 に答える
0

私は MySQL 構文は初めてですが、もう少し掘り下げると、動的クエリが機能する可能性があると思います。N 番目の行を選択します。ここで、N 番目はランダムです。

SELECT @r := CAST(COUNT(1)*RAND() AS UNSIGNED) FROM table WHERE column_x is null;

PREPARE stmt FROM
'SELECT * 
FROM table
WHERE column_x is null
LIMIT 1 OFFSET ?';

EXECUTE stmt USING @r;
于 2012-05-20T23:39:38.457 に答える