2

約 30k レコードで満たされた db テーブルがあります。

一度に 1 つずつランダムにレコードを選択し (ユーザーが要求した場合)、テーブルからレコードを削除し、別のテーブルに挿入したいと考えています。

ORDER BY RAND()実行が非常に遅くなる可能性があることを聞いた/発見しました。だから私はこのアルゴリズム(疑似コード)を使用しています:

lowest = getLowestId(); //get lowest primary key id from table
highest = getHighestId(); //get highest primary key id from table

do
{
    id = rand(lowest, highest); //get random number between a range of lowest id and highest id
    idExists = checkIfRandomIdExists( id );
}
while (! idExists);

row = getRow (id);
process(row);
delete(id);

現在、30,000 件のレコードがあり、ランダム ID を非常に迅速に取得しているようです。ただし、テーブルのサイズが 15k、10k、5k、100 などに減少するにつれて (数か月になる場合もあります)、これが遅くなり始めるのではないかと心配しています。

この方法をより効果的にするために何かできることはありますか、またはORDER BY RAND()この方法の代わりに行数を開始する必要がある点はありますか? (たとえば、5k 行が残ったら、ORDER BY RAND() を開始しますか?)

4

3 に答える 3

3

その方法を使用してランダムな ID を取得できますが、存在するかどうかを確認する代わりに、最も近い ID を取得してみてください。

SELECT * FROM table WHERE id >= $randomId ORDER BY id LIMIT 0,1

それが失敗した場合は、より低いものを選びます。

于 2012-05-11T21:08:10.333 に答える
3

それを行う 1 つの方法は、レコードの数を決定し、レコードごとに選択することです。

select floor(count(*) * rand()) from thetable;

結果のレコード番号 (例: chosenrec) を制限に使用します。

select * from thetable limit chosenrec, 1;
于 2012-05-11T21:11:47.810 に答える
2

代わりに、別の表でフィッシャー・イェーツ・シャッフルをお勧めするかもしれません. これを生成するには、次のようなテーブルを作成します。

CREATE TABLE Shuffle
(
    SequentialId INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    OtherTableId INT NOT NULL
)

特に、外部キー制約を気にしないでください。たとえば、SQL Server では、外部キー制約をON DELETE CASCADE;で追加すると言えます。MySQL で実行可能なストレージ エンジンがある場合は、それを使用してください。

次に、選択した言語で:

  1. 他のテーブルのすべての ID の配列を取得します (コメントで @Truth が提案したように)。
  2. Fisher-Yates を使用してこれらの ID をシャッフルします (線形時間がかかります)。
  3. Shuffleそれらを順番にテーブルに挿入します。

これでランダムな順序ができたのでINNER JOINShuffleテーブルにORDER BY Shuffle.SequentialId移動してから最初のレコードを見つけることができます。Shuffleやむを得ない場合は、手動でレコードを削除できますON DELETE CASCADE

于 2012-05-11T21:13:55.080 に答える