быстрый выбор случайной строки из большой таблицы в MySQL - PullRequest
44 голосов
/ 17 октября 2008

Какой быстрый способ выбрать случайную строку из большой таблицы MySQL?

Я работаю в php, но меня интересует любое решение, даже если оно на другом языке.

Ответы [ 24 ]

46 голосов
/ 17 октября 2008

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

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

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

Если вы сделаете заказ случайным образом, на ваших руках будет ужасное сканирование таблицы, и слово quick не относится к такому решению.

Не делайте этого, и вы не должны заказывать по GUID, у него та же проблема.

37 голосов
/ 17 октября 2008

Я знал, что должен быть способ сделать это в одном запросе быстрым способом. И вот оно:

Быстрый путь без привлечения внешнего кода, слава

http://jan.kneschke.de/projects/mysql/order-by-rand/

SELECT name
  FROM random AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(id)
                        FROM random)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1;
30 голосов
/ 18 октября 2008

MediaWiki использует интересный трюк (для функции Wikipedia Special: Random): в таблице со статьями есть дополнительный столбец со случайным числом (генерируемым при создании статьи). Чтобы получить случайную статью, сгенерируйте случайное число и получите статью со следующим большим или меньшим (не помню, какое) значением в столбце случайного числа. С индексом это может быть очень быстро. (А MediaWiki написана на PHP и разработана для MySQL.)

Этот подход может вызвать проблему, если полученные числа плохо распределены; IIRC, это было исправлено в MediaWiki, поэтому, если вы решите сделать это таким образом, вам следует взглянуть на код, чтобы увидеть, как это делается в настоящее время (возможно, они периодически генерируют столбец случайных чисел).

12 голосов
/ 17 октября 2008

Вот решение, которое работает довольно быстро и получает лучшее случайное распределение, не зависящее от того, что значения id являются смежными или начинаются с 1.

SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM mytable)));
SET @sql := CONCAT('SELECT * FROM mytable LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;
3 голосов
/ 27 сентября 2008

Может быть, вы могли бы сделать что-то вроде:

SELECT * FROM table 
  WHERE id=
    (FLOOR(RAND() * 
           (SELECT COUNT(*) FROM table)
          )
    );

Предполагается, что все ваши идентификационные номера последовательны без пробелов.

3 голосов
/ 27 сентября 2008

Добавьте столбец, содержащий вычисленное случайное значение, в каждую строку и используйте его в предложении упорядочения, ограничиваясь одним результатом при выборе. Это работает быстрее, чем сканирование таблицы, которое вызывает ORDER BY RANDOM().

Обновление: Вам все еще нужно вычислить какое-то случайное значение до выдачи оператора SELECT при получении, конечно, например,

SELECT * FROM `foo` WHERE `foo_rand` >= {some random value} LIMIT 1
1 голос
/ 25 января 2011

Чтобы найти случайные строки в таблице, не используйте ORDER BY RAND (), потому что это заставляет MySQL выполнить полную сортировку файлов и только затем получать требуемое количество строк. Чтобы избежать такой полной сортировки файлов, используйте функцию RAND () только в предложении where. Он остановится, как только достигнет необходимого количества строк. Увидеть http://www.rndblog.com/how-to-select-random-rows-in-mysql/

1 голос
/ 01 июня 2010

, если вы не удалите строку в этой таблице, самый эффективный способ:

(если вы знаете идентификатор mininum, просто пропустите его)

SELECT MIN(id) AS minId, MAX(id) AS maxId FROM table WHERE 1

$randId=mt_rand((int)$row['minId'], (int)$row['maxId']);

SELECT id,name,... FROM table WHERE id=$randId LIMIT 1
1 голос
/ 01 декабря 2009

Существует еще один способ получения случайных строк, используя только запрос и без упорядочения rand () Он включает в себя пользовательские переменные. См. , как получить случайные строки из таблицы

1 голос
/ 23 апреля 2009

Для выбора нескольких случайных строк из данной таблицы (скажем, «слова») наша команда придумала такую ​​красоту:

SELECT * FROM
`words` AS r1 JOIN 
(SELECT  MAX(`WordID`) as wid_c FROM `words`) as tmp1
WHERE r1.WordID >= (SELECT (RAND() * tmp1.wid_c) AS id) LIMIT n
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...