MySQL:选择多个随机行的最有效方法是什么

时间:2012-04-07 13:19:08

标签: mysql sql random

我有一个相当大的数据集和一个需要两个连接的查询,因此查询的效率对我来说非常重要。我需要从数据库中检索3个随机行,这些行满足基于连接结果的条件。 Most obvious solution被指出效率低here,因为

  

[这些解决方案]需要对所有表进行顺序扫描(因为需要计算与每行关联的随机值 - 以便可以确定最小的一行),这对于中等大小的表来说可能非常慢。

但是,作者在那里建议的方法(SELECT * FROM table WHERE num_value >= RAND() * (SELECT MAX(num_value) FROM table) LIMIT 1,其中num_value是ID)对我不起作用,因为某些ID可能会丢失(因为某些行可能已被用户删除)。

那么,在我的情况下检索3个随机行的最有效方法是什么?

编辑:解决方案不需要是纯SQL。我也使用PHP。

2 个答案:

答案 0 :(得分:2)

将您的RAND()调用添加到ORDER BY子句中应该允许您忽略该ID。试试这个:

SELECT * FROM table WHERE ... ORDER BY RAND() LIMIT 3;

在指出性能问题之后,您最好的选择可能是这些方面(使用PHP):

$result = PDO:query('SELECT MAX(id) FROM table');
$max    = $result->fetchColumn();
$ids    = array();
$rows   = 5;

for ($i = 0; $i < $rows; $i++) {
    $ids[] = rand(1, $max);
}

$ids     = implode(', ', $ids);
$query   = PDO::prepare('SELECT * FROM table WHERE id IN (:ids)');
$results = $query->execute(array('ids' => $ids));

此时您应该能够选择前3个结果。这种方法的唯一问题是处理已删除的行,您可能必须碰撞$ rows var或添加一些逻辑来执行另一个查询,以防您没有收到至少3个结果。

答案 1 :(得分:2)

由于您不需要很多结果,因此使用LIMITOFFSET会有一些有趣的选项。

我将假设id列是唯一且适合排序的。

第一步是执行COUNT(id),然后在PHP中从0COUNT(id) - 1选择随机3个数字。 (如何做到这一点是一个单独的问题,最好的方法取决于总行数和你想要的数量。)

第二步有两个选择。假设您选择的随机数为0,15,2234。要么在PHP中有一个循环

// $offsets = array(0, 15, 2234);
foreach ($offsets as $offset) {
    $rows[] = execute_sql('SELECT ... ORDER BY id LIMIT 1 OFFSET ?', $offset);
}

或构建UNION。注意:这需要子选择,因为我们正在使用ORDER BY。

// $offsets = array(0, 15, 2234);
$query = '';
foreach ($offsets as $index => $offset) {
    if ($query) $query .= ' UNION ';
    $query .= 'SELECT * FROM (SELECT ... ORDER BY id LIMIT 1 OFFSET ?) Sub'.$index;
}
$rows = execute_sql($query, $offsets);