Forum Webscript.Ru

Общие => Базы данных => Тема начата: tigranav от 06 Декабря 2006, 09:59:33

Название: Случайная картинка
Отправлено: tigranav от 06 Декабря 2006, 09:59:33
Как лучше сделать скрипт случайное фото?
Исходные данные - таблица с картинками
У меня в  голове крутиться самый простой вариант:
 просто выгружать все картинки в массив, потом брать случайный номер и выводить

Может быть есть более правильный метод?
Название: Случайная картинка
Отправлено: html_coder от 06 Декабря 2006, 10:43:02
Если эта таблица в базе (мало ли какая таблица может быть)

то можно например так
Таким запросом получаешь общее колиеч



$result = mysql_query(\'SELECT COUNT(*) as images_count FROM images\');
$images_count = mysql_result($result, 0, 0);
random_image = rand(0, $images_count);

//Случайное изображение
mysql_query(\'SELECT * FROM images LIMIT \'.$random_image.\',1);



Вот примерно так можно попробовать.
Название: Случайная картинка
Отправлено: tigranav от 06 Декабря 2006, 10:56:25
Да, именно так я и думал. Просто хотелось узнать, может быть как то по другому будет быстро...

Спасибо за ответ.
Название: Случайная картинка
Отправлено: Egorsha от 08 Декабря 2006, 09:16:20
По другому тоже можно. И быстрее будет. Но это тема другой ветки форума.

SELECT *  FROM images ORDER BY RAND() LIMIT 1

- всего один запрос.
Название: Случайная картинка
Отправлено: tigranav от 08 Декабря 2006, 09:25:57
А какой ветки?
Это полный запрос или в RAND нужно писать параметры?
Название: Случайная картинка
Отправлено: Egorsha от 08 Декабря 2006, 10:06:23
Это полный запрос. Поменяй только название базы, если не совпадает.

А ветка скорее всего "Базы данных".
Там кстати такое уже обсуждалось - одна случайная запись из базы.
Название: Случайная картинка
Отправлено: tigranav от 08 Декабря 2006, 10:10:00
Примного благодарен.
Название: Случайная картинка
Отправлено: html_coder от 08 Декабря 2006, 10:43:40
Цитировать
Egorsha:
По другому тоже можно. И быстрее будет. Но это тема другой ветки форума.

 SELECT * FROM images ORDER BY RAND() LIMIT 1

 - всего один запрос.


Egorsha, а вы уверены что это будет быстрее???

А если таблица будет большая?

Из документации по MySQL:

В выражениях вида ORDER BY не следует использовать столбец с величинами RAND(), поскольку применение оператора ORDER BY приведет к многократным вычислениям в этом столбце.
Название: Случайная картинка
Отправлено: Egorsha от 08 Декабря 2006, 12:03:12
Если уж очень интересно, то попытаюсь ответить...
(Хотя сейчас, после переноса топика в другую ветку - опять разговор не по теме получится.)

На счет уверенности - скорее уверен в том, что ни в чем не уверен.

Но осмелюсь заметить, что в заданном вопросе не уточнялась какая база используется. (Решили, что MySQL - типа "по умолчанию"). А вдруг у других БД в документации по иному прописано.

Быстрее? Можно проверить на опыте, в данном конкретном случае (это дело задавшего вопрос).

И еще хочу объяснить, то почему ответил в этом топике.
Мне просто не понравился первоначальный  Ваш ответ. :)

Почему?  

Все просто -  приведенный Вами код делает не то, о чем спрашивали.

Построчно:
- запрос на количество записей в таблице;
- получение количества записей;
- случайное число N в интевале от "нуля" до "количество записей"
-... и наконец получение N первых записей из таблицы (но не одной случайной)

При Вашем подходе к поставленному вопросу, нужно сделать выборку всех записей (при большой базе - получится большой массив), в посчитать количество элементов массива, случайным образом выбрать элемент массива, содержащий id-записи и по этому id получить запись из базы. Нумерация записей может быть не скозной, а с пробелами (к примеру записи id=999 может не быть в базе, а N=999).

И что так быстрее будет (если база большая)?

И, кстати, вместо функции rand()  лучше бы воспользоваться mt_rand()....

Но от темы уже ушли.

Может закрыть эту тему? а?
Название: Случайная картинка
Отправлено: for_i_0 от 08 Декабря 2006, 13:00:27
Egorsha
[OFF]Пожалуй, подождем html_coder - а.[/OFF]
Название: Случайная картинка
Отправлено: html_coder от 08 Декабря 2006, 13:13:36
Цитировать
Egorsha:
Может закрыть эту тему? а?


Нет, от чего же закрыть, тему надо развить...

Значит ещё раз смотрим внимательно мой пример.

1) Где в моем коде я перекладываю всё полученное из базы в массив?
2)
Цитировать
Egorsha:
и наконец получение N первых записей из таблицы (но не одной случайной)


А это где?

Смотрим сюда Что какое LIMIT n,m (http://dev.mysql.com/doc/refman/5.0/en/select.html)

Проще говоря запрос выбирает одну запись со смещения $random_image,  которое как вы правильно поняли будет в интервале от 0 до количества изображений, т.е. гаранитировано я выберу одну запись и 100% случайную... Где привязка к ID? В данном случае абсолютно всё равно какие ID есть в базе а каких нет?

По поводу быстродействия утверждать не буду надо проверять, но практически уверен, что на огрмной таблице ORDER BY RAND() будет работать медленнее (сталкивался с ним), при чем гораздо!
Название: Случайная картинка
Отправлено: Egorsha от 08 Декабря 2006, 14:25:35
Все сдаюсь ;)

Цитировать
html_coder:
...ещё раз смотрим внимательно мой пример...


И это правильно - не доглядел ;)

mysql_query(\'SELECT * FROM images LIMIT \'.$random_image.\',1);

Увидел это, и воспринял "неправильно", типа так:


mysql_query(\'SELECT * FROM images LIMIT \'.$random_image,1);


отсюда "LIMIT n", "первые n" и т.д.
(Только давай этот второй параметр "1" не будем развивать в продолжение темы ;) Он меня слегка смутил, но так как давно уже написан класс работы с базой и я "явно" этой функцией так же давно не пользуюсь (и вряд ли "явно" воспользуюсь)).

А вот если бы я "правильно" увидел:

mysql_query(\'SELECT * FROM images LIMIT \'.$random_image.\',1\');


То сразу бы заметил LIMIT n,m :) (Ну, а что делать, я тоже могу ошибаться. Вон нет "кавычки" и все ОК. :))

И вот уже интересно, чес слово, все это проверить, что быстрее.
Из всех таблиц, что  есть в распоряжении одна с 7200 записями. Потянет за "огромную"? (Другой просто нет).
Или "чистота эксперимента" не будет соблюдена?

Тему надеюсь не закроют до окончания "эксперимента"? :)
Название: Случайная картинка
Отправлено: Yukko от 08 Декабря 2006, 14:49:03
Цитировать
А вдруг у других БД в документации по иному прописано.

Насколько я понимаю, принцип работы других РСУБД будет таким же ;) Берется таблица, делается полная выборка (если нет лимит), а после этого из общей массы выбирается что-то случайное.

Я в код MySQL не смотрел, пусть меня поправят те, кто смотрел, но про механизм образования этого "случайного" я могу догадаться проведя эксперимент:
select * from table order by 1
select * from table order by 2
select * from table order by 3
select * from table order by n
где n — количество полей в таблице.
Если ORDER BY RAND() случайно где-то сортирует таблицу по одному из случайно выбранных полей, а потом берет случайную запись из получившегося результата, то можно себе представить, что будет, если сортировка будет проводиться на таблице с миллионом записей и по полю, по которому нет индекса.

Делать ORDER BY RAND() на больших таблицах без LIMIT, детально не разобравшись, сколько рядков будет просмотрено, чтобы вернулся  запрошенный результат, по которому будет делаться ORDER BY RAND(), я бы не стал ;) склеит ласты, потом не расклеишь. Судя по всему, в мануале не зря написан пример:
mysql> SELECT * FROM table1, table2 WHERE a=b AND c ORDER BY RAND() LIMIT 1000;
http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html

Цитировать
Egorsha:
Все просто - приведенный Вами код делает не то, о чем спрашивали.

а если попробовать разобраться с LIMIT?
Название: Случайная картинка
Отправлено: tigranav от 08 Декабря 2006, 14:49:26
Из дискуссии я понял что лучше использовать пример html_coder-а
mysql_query(\'SELECT * FROM images LIMIT \'.$random_image.\',1\');
Название: Случайная картинка
Отправлено: Egorsha от 08 Декабря 2006, 17:49:59
Цитировать
Yukko:
а если попробовать разобраться с LIMIT?


Выше написал -  не правильно трактовал отсутствующую "кавычку" в коде html_coder-а. Отсюда и LIMIT n вместо LIMIT n,m и все остальное вытекающее... и т.д. и т.п.

Уважаемый html_coder, если я, пребывая в невольном заблуждении, все же умудрился чем-то оскорбить Вас (а цели такой не преследовал, мотивации описал выше), то просьба извинить меня.

Теперь проведенный "эксперимент".
Код (отрицательные значения лечатся F5 - не стал обрабатывать различные секунды):

$table="...";
$tm1=gettimeofday();
$result = mysql_query(\'SELECT COUNT(*) as images_count FROM \'.$table);
$images_count = mysql_result($result, 0, 0);
$random_image = rand(0, $images_count);
mysql_query(\'SELECT * FROM \'.$table.\' LIMIT \'.$random_image.\',1\');
$tm2=gettimeofday();
$tmp1=$tm2[\'usec\']-$tm1[\'usec\'];
$tm1=gettimeofday();
mysql_query(\'SELECT * FROM \'.$table.\' ORDER BY RAND() LIMIT 1\');
$tm2=gettimeofday();
$tmp2=$tm2[\'usec\']-$tm1[\'usec\'];
echo "Записей: ".$images_count."
";
echo "Время работы: ".$tmp1." - микросекунд
";
echo "Время работы: ".$tmp2." - микросекунд
";
echo "K =".($tmp2/$tmp1)."
";


Результаты: (можете сами проверить кому интересно)

При использовании ORDER BY RAND() работает в общем медленнее.
- На меленьких таблицах разница есть, но маленькая - десятки-сотни микросекунд.
- На таблице побольше уже ощутимее:

По минимуму где-то так:

Время работы: 21540 - микросекунд
Время работы: 129674 - микросекунд
Записей: 7811
K =6.02014856082

По максимуму может вылезти и намного выше. (Выпадало и К=130.)

- Если записи по объему большие (например, картинка лежит в поле таблицы), то время работы запроса увеличивается и в одном и втором случае, а коэффициент K в принципе не меняется.
 
Цитировать
tigranav:
Из дискуссии я понял что лучше использовать пример html_coder-а


Если большая база и критично время - то именно так.
Название: Случайная картинка
Отправлено: html_coder от 08 Декабря 2006, 19:53:32
Цитировать
Egorsha:
Уважаемый html_coder, если я, пребывая в невольном заблуждении, все же умудрился чем-то оскорбить Вас (а цели такой не преследовал, мотивации описал выше), то просьба извинить меня.


Ни в коем случае не оскорбили, просто хотелось развернуть тему. Тема развернута великолепно. Думаю tigranav получил исчерпывающий ответ на свой вопрос, да еще с выкладками по времени...

Думаю, что теперь тему можно точно закрывать )))