Forum Webscript.Ru
Общие => Базы данных => Тема начата: tigranav от 06 Декабря 2006, 09:59:33
-
Как лучше сделать скрипт случайное фото?
Исходные данные - таблица с картинками
У меня в голове крутиться самый простой вариант:
просто выгружать все картинки в массив, потом брать случайный номер и выводить
Может быть есть более правильный метод?
-
Если эта таблица в базе (мало ли какая таблица может быть)
то можно например так
Таким запросом получаешь общее колиеч
$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);
Вот примерно так можно попробовать.
-
Да, именно так я и думал. Просто хотелось узнать, может быть как то по другому будет быстро...
Спасибо за ответ.
-
По другому тоже можно. И быстрее будет. Но это тема другой ветки форума.
SELECT * FROM images ORDER BY RAND() LIMIT 1
- всего один запрос.
-
А какой ветки?
Это полный запрос или в RAND нужно писать параметры?
-
Это полный запрос. Поменяй только название базы, если не совпадает.
А ветка скорее всего "Базы данных".
Там кстати такое уже обсуждалось - одна случайная запись из базы.
-
Примного благодарен.
-
Egorsha:
По другому тоже можно. И быстрее будет. Но это тема другой ветки форума.
SELECT * FROM images ORDER BY RAND() LIMIT 1
- всего один запрос.
Egorsha, а вы уверены что это будет быстрее???
А если таблица будет большая?
Из документации по MySQL:
В выражениях вида ORDER BY не следует использовать столбец с величинами RAND(), поскольку применение оператора ORDER BY приведет к многократным вычислениям в этом столбце.
-
Если уж очень интересно, то попытаюсь ответить...
(Хотя сейчас, после переноса топика в другую ветку - опять разговор не по теме получится.)
На счет уверенности - скорее уверен в том, что ни в чем не уверен.
Но осмелюсь заметить, что в заданном вопросе не уточнялась какая база используется. (Решили, что MySQL - типа "по умолчанию"). А вдруг у других БД в документации по иному прописано.
Быстрее? Можно проверить на опыте, в данном конкретном случае (это дело задавшего вопрос).
И еще хочу объяснить, то почему ответил в этом топике.
Мне просто не понравился первоначальный Ваш ответ. :)
Почему?
Все просто - приведенный Вами код делает не то, о чем спрашивали.
Построчно:
- запрос на количество записей в таблице;
- получение количества записей;
- случайное число N в интевале от "нуля" до "количество записей"
-... и наконец получение N первых записей из таблицы (но не одной случайной)
При Вашем подходе к поставленному вопросу, нужно сделать выборку всех записей (при большой базе - получится большой массив), в посчитать количество элементов массива, случайным образом выбрать элемент массива, содержащий id-записи и по этому id получить запись из базы. Нумерация записей может быть не скозной, а с пробелами (к примеру записи id=999 может не быть в базе, а N=999).
И что так быстрее будет (если база большая)?
И, кстати, вместо функции rand() лучше бы воспользоваться mt_rand()....
Но от темы уже ушли.
Может закрыть эту тему? а?
-
Egorsha
[OFF]Пожалуй, подождем html_coder - а.[/OFF]
-
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() будет работать медленнее (сталкивался с ним), при чем гораздо!
-
Все сдаюсь ;)
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 записями. Потянет за "огромную"? (Другой просто нет).
Или "чистота эксперимента" не будет соблюдена?
Тему надеюсь не закроют до окончания "эксперимента"? :)
-
А вдруг у других БД в документации по иному прописано.
Насколько я понимаю, принцип работы других РСУБД будет таким же ;) Берется таблица, делается полная выборка (если нет лимит), а после этого из общей массы выбирается что-то случайное.
Я в код 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?
-
Из дискуссии я понял что лучше использовать пример html_coder-а
mysql_query(\'SELECT * FROM images LIMIT \'.$random_image.\',1\');
-
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-а
Если большая база и критично время - то именно так.
-
Egorsha:
Уважаемый html_coder, если я, пребывая в невольном заблуждении, все же умудрился чем-то оскорбить Вас (а цели такой не преследовал, мотивации описал выше), то просьба извинить меня.
Ни в коем случае не оскорбили, просто хотелось развернуть тему. Тема развернута великолепно. Думаю tigranav получил исчерпывающий ответ на свой вопрос, да еще с выкладками по времени...
Думаю, что теперь тему можно точно закрывать )))