Случайная выборка из базы данных и её оптимизация

Опубликовано Опубликовано в рубрике PHP, SQL

Наверное, каждый сталкивался с задачей выборки случайных записей из базы данных. Казалось бы, SQL обладает встроенной функцией RAND(), но не все так просто. Есть и подводные камни!
Для начала стоит рассмотреть функцию RAND() на практике. Пусть нам необходимо выбрать 3 случайных записи из какой-либо таблицы. На ум сразу же приходит следующая конструкция:

SELECT * FROM `table` ORDER BY RAND() LIMIT 3

С точки зрения логики она абсолютно правильна. Но знание принципа её работы может очень расстроить клиента и разработчика. По сути, SQL-функция RAND() обходит ВСЮ таблицу, а после этого перемешивает её. Если идти дальше по выше приведённой конструкции, то получается, что для 3 случайных записей мы должны выгрузить всю таблицу! Нагрузка такого подхода будет ощутима уже на 4-хзначных значениях количества строк в таблице.

Мириться с этим нельзя! Оптимизируем решение нашей задачи при помощи PHP.

Для начала узнаем, сколько строк вернет нам запрос без ограничения на вывод:

$count = SELECT COUNT(*) FROM `table`;

Дальнейшая работа будет таковой: мы выполняем три запроса вместо одного, каждый из которых возвращает одну строку из таблицы со случайным номером. Как это сделать? Нам поможет PHP-функция rand(). Она возвращает случайное число из заданного пользователем диапазона. Наша область выборки будет колебаться от 0 до числа $count.

В цикле от 0 до 3 будет сгенерировано 3 запроса строк со случайным номером. Это будет выглядеть примерно вот так:

$zapros = array();
while (count($zapros) < 3) {
$zapros[] = '(SELECT * FROM `table` LIMIT '.rand(0, $count).', 1)';
}

Запись LIMIT '.rand(0, $count).', 1 означает, что мы выбираем 1 строку со случайным номером из всего диапазона.

Но как объединить эти запросы? Тут на помощь приходит SQL-функция UNION, которая выводит все результаты запросов в единую таблицу. Саму таблицу мы впоследствии и будем обрабатывать как массив.

$zapros = implode(' UNION ', $zapros);

PHP-функция implode() возвращает строку, полученную объединением строковых представлений элементов массива $zapros, со вставкой строки ' UNION ' между соседними элементами.

Теперь уже можно обратиться к базе данных и послать в неё сгенерированный нами запрос:

$zapros = mysql_query($zapros);

Прирост скорости работы на больших таблицах заметен невооруженным глазом! К примеру, на проекте в 150 тысяч строк скорость выполнения задачи увеличилась в 4 раза. Думаю, это весомый аргумент!

За сим все!

Безошибочного Вам кода!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *