Выборка случайной записи из таблицы базы данных MySQL

Выборка случайной записи из таблицы базы данных MySQL

Простейшим способом отбора записей из базы данных MySQL является “ORDER BY RAND()” в условии запроса.

Решение 1

[SQL]
 

SELECT * FROM `table` ORDER BY RAND() LIMIT 0,1;

Проблемой этого метода есть то, что он очень медленный. Причиной такого медленного выполнения есть то, что MySQL создает временную таблицу со всеми результирующими записями и назначает каждой из них случайный индекс сортировки. Результат сортируется и возвращается.

Есть несколько приемов ускорить это.

Основная идея это получить случайный номер и тогда выбрать определенную запись используя этот номер.

В случае если все номера имеют уникальные ID мы будем выбирать случайный номер между наименьшим и наибольшим ID и затем выберем запись с ID что соответствует этому номеру. Что бы сделать этот способ рабочим когда ID распределены не равномерно будем использовать “>=” оператор вместо “=” в последнем запросе.

Получить минимальное и максимальное значение ID в заданной таблице мы будем использовать MAX() и MIN() обобщающие функции. Эти функции будут возвращать минимальное и максимальное значение в определенных группах. Группа в нашем случае это все значения ID колонки в нашей таблице.

Решение 2

[PHP]

$range_result = mysql_query( ” SELECT MAX(`id`) AS max_id , MIN(`id`) AS min_id FROM `table` “);
$range_row = mysql_fetch_object( $range_result );
$random = mt_rand( $range_row->min_id , $range_row->max_id );
$result = mysql_query( ” SELECT * FROM `table` WHERE `id` >= $random LIMIT 0,1 “);

Как вы заметили этот метод ограничивается таблицами с уникальными ID для каждой записи. Что делать если у нас другая таблица?

Решением может быть использование MySQL LIMIT условия. LIMIT принимает два аргумента. Первый аргумент определяет сдвиг первой записи для выборки, и второй определяет максимальное количество записей для выборки. По умолчанию для сдвига назначается число 0 (не 1).

Вычислять сдвиг к первой записи мы будем генерируя случайный номер между 0 и 1 используя MySQL’s RAND() функцию. Затем мы умножим получившееся на количество записей в таблице, которые получим используя COUNT() функцию. Далее LIMIT аргументы должны задаваться как целые а не дробные значения поэтому заокруглим получившееся значение используя FLOOR() функцию. FLOOR() это арифметическая функция что вычисляет наибольее целое значение что меньше или равно заданному. Результирующий код будет выглядеть так:

Решение 3

[PHP]

$offset_result = mysql_query( ” SELECT FLOOR(RAND() * COUNT(*)) AS `offset` FROM `table` “);
$offset_row = mysql_fetch_object( $offset_result );
$offset = $offset_row->offset;
$result = mysql_query( ” SELECT * FROM `table` LIMIT $offset, 1 ” );

В MySQL 4.1 и более поздних версиях мы можем комбинировать два предыдущих метода использую подзапросы:

Решение 4

[SQL]

SELECT * FROM `table` WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` ) ORDER BY id LIMIT 1;

Это решение имеет тоже слабое место что и Решение 2, то есть оно работает только с таблицами с уникальными ID.

Помните причину по который мы начали искать альтернативный способ выборки случайной записи? Скорость! Итак как сравнить эти методы по времени выполнения. Я не буду вдаваться в описание железа и настроек программного обеспечения. Приблизительный результат:

  • Медленнее всех оказался метод для Решения 1. Это будет 100% времени на выполнение.
  • Решение 2 – занял 79%
  • Решение 3 – 13%
  • Решение 4 – 16%

Победителем оказалось Решение 3.