Как правильно вытянуть рандомные значения с БД

yantar

Новичок
Как правильно вытянуть рандомные значения с БД

Не знаю, правильно ли названа тема.
Суть такова - есть галерея - категории с картинками.
Для категории используется рандомная картинка с галереи.

Вижу 2 варианта, но ни один из них мне не нравится

1. Тянуть для каждой категории рандомный рисунок ( если 50 категорий на странице - 50 лишних запросов к бд).
2. Тяну все рисунки с таблицы рисунков и на ПХП прохожу по циклу и рандомом выбираю рисунок для категории (не нравится, потому, что если будет очнь много рисунков - тогда много данных буду с бд дергать).

Пробовал делать одним запросом через order by rand() - не выходит (да и пишут, что использовать order by rand() не очень хорошо ).

Или в этом случае - лучше пробовать в реальных условиях на реальном количестве категорий и рисунков и смотреть, как будет быстрее ?
 

Adelf

Administrator
Команда форума
Если для каждой категории хранить(и обновлять) количество рисунков в ней, то можно сначала сделать rand() с нужными параметрами, а потом уже запрос с LIMIT одной записи.

З.Ы. когда я решал данную проблему я знал что у меня в категории всегда больше 10 картинок и выбирал одну из последних 10.
 

yantar

Новичок
2 Adelf - вы предлагает вариант 1 - то есть количество запросов = количеству категорий.
 

iceman

говнокодер
yantar
PHP:
SELECT
  t.cat_id, t.cat_name, 
  (SELECT x.image FROM images as x WHERE x.cat_id = t.cat_id
   ORDER BY rand() LIMIT 1)  as image
FROM catagory as t
может что-то типа такого :D

только добавить (обязательно) в под запросе условие которое предложил Adelf (последние 10 картинок)
 

Adelf

Administrator
Команда форума
Я тут подумал - грамотный кеш результатов избавит от любых проблем с производительностью. Хранить в кеше последние 20-30(хоть 100) картинок в каждой категории и проблема решена.
 

yantar

Новичок
Автор оригинала: iceman
yantar
PHP:
SELECT
  t.cat_id, t.cat_name, 
  (SELECT x.image FROM images as x WHERE x.cat_id = t.cat_id
   ORDER BY rand() LIMIT 1)  as image
FROM catagory as t
может что-то типа такого :D
Да, такое прокатило.
 

iceman

говнокодер
добавь еще таблицу в которой будет cat_id, image_id (связь многие-ко-многим) и сам будешь выбирать какие картинки туды добавлять, так как записей там будет не много, то на счет rand(), думаю, можно будет не беспокоиться...
 

Andre

Новичок
1. Считаем количество картинок в категории через COUNT
2. Генерим случайное число от 0 до COUNT
3. Выбираем картинку ограничивая через LIMIT 1 OFFSET сгенерированное число

Работает быстро на довольно больших объемах

А вообще где то на хабре все это разжевывали с тестами и замерами
 

Adelf

Administrator
Команда форума
Да в этой теме тоже кагбэ успели расжевать.
 

Dreammaker

***=Ф=***
> 3. Выбираем картинку ограничивая через LIMIT 1 OFFSET сгенерированное число

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

Поэтому лучше получить максимальное значение ID . Затем в промежутке от 1 до полученного MAX(id) нагенерить в 10-40 hfp больше чем требуется, значений id.

И по ним отдельными запросами (SELECT * form table WHERE id = random_number LIMIT 1) или с помощью юнион получить штук 100 (или сколько там получится) строк таблицы.

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

Не каждый из запросов с id = random_number вернёт заполненную строку, будут и пустые, но это не так страшно.

Кроме того, через некоторое время пользователь может заметить что некоторые рендом-значения повторяются, но на практике на рандом значения (если это посты, товары и т.д.) смотрят в основном новички, а они страниц 10 только и просмотрят, а те кто постоянно сидят на сайте не часто смотрят на случайные посты, товары и т.д.
 

zerkms

TDD infected
Команда форума
Dreammaker
фикня, на больших размерах таблицы будет сказываться сортировка, особенно, если таблица будет содержать текстовые поля.
откуда у тебя взялась сортировка?
SELECT * FROM `table` LIMIT $rand_offset, 1

а вот твоя выборка будет неравномерная, сам упомянул.
 

Dreammaker

***=Ф=***
Сейчас глянул, действительно насчёт сортировки ступил. :) Каюсь, файлсорта нету.

Но в любом случае вот такой запрос (первая попавшая оказалась база от дле):

EXPLAIN SELECT * FROM `dle_post` LIMIT 4100 , 1

показывает следующее:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE dle_post ALL NULL NULL NULL NULL 4338

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

p.s. или точнее MySQL собирается их пересмотреть, там уже как карта ляжет. :)
 

zerkms

TDD infected
Команда форума
Dreammaker
ещё бы - у тебя нет условия, по которому данные отсекутся.. другое дело, если там FIXED ROW (нету блобов, варчаров, текста) тогда смещение вычисляется мгновенно и запись возвращается тоже мгновенно. в противном случае идёт сик от начала файла до N-ной записи.
 
Сверху