Как эффективно выбрать случайную запись в MySQL? - PullRequest
5 голосов
/ 25 апреля 2010
mysql> EXPLAIN SELECT * FROM urls ORDER BY RAND() LIMIT 1;
+----+-------------+-------+------+---------------+------+---------+------+-------+---------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra                           |
+----+-------------+-------+------+---------------+------+---------+------+-------+---------------------------------+
|  1 | SIMPLE      | urls  | ALL  | NULL          | NULL | NULL    | NULL | 62228 | Using temporary; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+-------+---------------------------------+

Выше не квалифицируется как эффективный, как я должен сделать это правильно?

UPDATE

Кажется, использование решения, упомянутого в ответе, все еще не помогает:

mysql> explain SELECT  *
    -> FROM    (
    ->         SELECT  @cnt := COUNT(*) + 1,
    ->                 @lim := 10
    ->         FROM    urls
    ->         ) vars
    -> STRAIGHT_JOIN
    ->         (
    ->         SELECT  r.*,
    ->                 @lim := @lim - 1
    ->         FROM    urls r
    ->         WHERE   (@cnt := @cnt - 1)
    ->                 AND RAND(20090301) < @lim / @cnt
    ->         ) i;
+----+-------------+------------+--------+---------------+------+---------+------+-------+------------------------------+
| id | select_type | table      | type   | possible_keys | key  | key_len | ref  | rows  | Extra                        |
+----+-------------+------------+--------+---------------+------+---------+------+-------+------------------------------+
|  1 | PRIMARY     | <derived2> | system | NULL          | NULL | NULL    | NULL |     1 |                              |
|  1 | PRIMARY     | <derived3> | ALL    | NULL          | NULL | NULL    | NULL |    10 |                              |
|  3 | DERIVED     | r          | ALL    | NULL          | NULL | NULL    | NULL | 62228 | Using where                  |
|  2 | DERIVED     | NULL       | NULL   | NULL          | NULL | NULL    | NULL |  NULL | Select tables optimized away |
+----+-------------+------------+--------+---------------+------+---------+------+-------+------------------------------+

Ответы [ 2 ]

4 голосов
/ 25 апреля 2010

Quassnoi написал сообщение о выборе строк в произвольном порядке без выполнения сортировки. Его пример выбирает 10 строк случайным образом, но вы можете адаптировать его для выбора только одной строки.

Если вы хотите, чтобы он был действительно быстрым, то вы можете использовать приближение, которое не будет полностью равномерным или иногда не сможет вернуть строку.

Вы также можете использовать хранимую процедуру для быстрого выбора случайной строки из Пост Билла Карвина :

SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM mytable)));
SET @sql := CONCAT('SELECT * FROM mytable LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

Обратите внимание, что в MyISAM это будет выполняться намного быстрее, чем в InnoDB, поскольку COUNT (*) стоит дорого в InnoDB, но почти мгновенно в MyISAM.

0 голосов
/ 25 апреля 2010

Что ж, если вы можете переместить некоторую логику на прикладной уровень (и я не понял ваш вопрос), тогда все, что вам нужно, это сгенерировать случайный идентификатор в вашем приложении и затем выполнить простой выбор для одной записи, идентифицируемой этим ключом.Все, что вам нужно знать, это количество записей.О, и если этот ключ был удален, получите следующий.

...