2

我有一个数据库表,里面有大约 30k 条记录。

我想一次随机选择一条记录(当用户要求时),从表中删除记录,然后将其插入另一个表中。

我听说/发现做起来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);

现在,有 30k 条记录,我似乎很快就得到了随机 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

一种方法可能是确定记录数并按记录选择:

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

在限制中使用生成的记录号(例如chosenrec):

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

我可能会在单独的表格中推荐Fisher-Yates Shuffle 。要生成它,请创建如下表:

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 回答