иногда встаёт задача случайной выборки записей из таблицы базы данных. на помощь приходит, как правило, старое, но не рекомендуемое решение:
SELECT *
FROM `articles`
ORDER BY RAND()
LIMIT 3;
данный запрос возвращает 3 случайных записи из таблицы `articles`. но если записей очень много и/или выборка достаточно сложная, формирование ответа может занимать секунды. ещё один минус — запрос не может быть закеширован. вернее даже кешировать можно, но с ограничениями. допустим, в течение 10 минут пользователи будут видеть одинаковые случайные новости. однако побороть такое поведение способ есть.
для этого на первом шаге придётся выполнить 2 запроса к базе. зато после первый запрос можно закешировать навечно (точнее на время, пока не будет добавлена/удалена запись из таблицы). на следующих шагах запрос к базе останется, но выполнятся он будет максимально быстро. итак, что у нас есть: таблица статей с первичным ключём `id` (напомню: значения первичного ключа уникальны; выборка по его значениям происходит очень быстро). код для иллюстрации:
// если есть собственный механизм кеширования, лучше использовать его
// для наибольшей производительности можно использовать memcache
// файл для хранения кеша
$cache_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'ids.cache';
// если файл существует
if (file_exists($cache_file)) { // получить значения из него
$ids = unserialize(file_get_contents($cache_file));
} else { // иначе, сформировать значения запросом
// получить все `id` таблицы
$query = SELECT `id` FROM `articles`';
$r = mysql_query($query);
$ids = array();
while ($n = mysql_fetch_row($r)) $ids[] = $n[0];
// записать полученные идентификаторы в файл
file_put_contents($cache_file, serialize($ids));
}
// теперь у нас есть идентификаторы всех первичных ключей
// перемешаем их
shuffle($ids);
// сделаем срез массива и получим требуемое количество (здесь 3)
$rand_ids = array_slice($ids, 0, 3);
// сформируем запрос на получение нужных статей
$query '
SELECT *
FROM `articles`
WHERE `id` IN (' . implode(',', $rand_ids) . ')
LIMIT 3';
// далее следует запрос к базе и получение записей
если записи в таблицу `articles` добавляются/удаляются, необходимо удалять файл кеша (для простоты). теперь, даже если первый запрос (для получения значений всех первичных ключей) будет достаточно долгий, это вполне компенсируется последующей скоростью выполнения. а на странице всегда будет список уникальных статей, чего, собственно, и добивались.
днём интернета
шоколадкой для работы мозга
коробочкой ароматного чая для бодрости
продлением хостинга на +1 месяц