这种从db中选择随机记录的方法有什么缺陷吗?

时间:2012-05-11 21:01:05

标签: php mysql performance algorithm

我有一个db表,里面有大约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);

现在,有了3万条记录,我似乎很快得到了随机ID。然而,随着表格大小减少到15k,10k,5k,100等(可能是几个月),我担心这可能会变慢。

我可以做任何事情来使这个方法更有效,或者是否有行数我应该开始做ORDER BY RAND()而不是这个方法? (例如,当剩下5k行时,开始执行ORDER BY RAND()?)

3 个答案:

答案 0 :(得分:3)

您可以使用该方法获取随机ID,但不是检查它是否存在,只是尝试获取最接近的ID?

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

然后,如果失败,请选择较低的。

答案 1 :(得分:3)

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

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

在限制中使用结果记录编号(例如chosenrec):

select * from thetable limit chosenrec, 1;

答案 2 :(得分: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表。
  4. 现在,您有一个随机订单,因此您只需INNER JOINShuffle表,然后ORDER BY Shuffle.SequentialId即可查找第一条记录。如果您无法Shuffle,则可以手动从ON DELETE CASCADE删除记录。