LINUX.ORG.RU

[SQL] SELECT ... ORDER RANDOM ...

 


0

0


есть: табличка в MySQL или PgSQL*, в ней есть какое то количество записей [переменное] включая ноль.

требуется: выбрать из таблички случайную запись.

решение влоб: получить кол-во записей, локально выбрать по рандому позицию, выбрать данные по позиции.

недостатки: неатомарность операции, накладные расходы в виде двух запросов да и просто некрасиво.

собственно хочется реализовать указанное средствами сервера. что то на вроде такого: SELECT a, b FROM foo WHERE c = 123 ORDER BY RANDOM LIMIT 1;

// wbr


ps: забыл "*" - в первую очередь, хочется для MySQL, но на решение для PgSQL то же было бы интересно взглянуть.

// wbr

klalafuda ★☆☆
() автор топика

>накладные расходы в виде двух запросов

Э-э-э, а почему двух?

Ну если оно умеет procedure то можно на серваке накропать процедурку и дергать ее...

А насколько важен именно рандом?

iRunix ★★★★
()
Ответ на: комментарий от iRunix

> Э-э-э, а почему двух?

ну точнее чуть чуть не так, как я описал. табличка имеет поле id типа SERIAL i.e. уникальный идентификатор каждой записи. таким образом, ламерско-влобный подход выглядит примерно так:

$ids = SELECT id FROM foo;
$id = get_random_id(ids);
$result = SELECT ... FROM foo WHERE id = $id;

те получаем полный список всех идентификаторов, выбираем случайный идентификатор и уже по нему выбираем конкретные данные. минусов у такого подхода хватает. хотя, конечно, при определённых ограничениях работает и он.

> Ну если оно умеет procedure то можно на серваке накропать процедурку и дергать ее...

хотелось бы обойтись малой кровью без stored proc :)

> А насколько важен именно рандом?

собственно важен именно рандом.

// wbr

klalafuda ★☆☆
() автор топика
Ответ на: комментарий от Anoxemian

> SELECT ... FROM foo ORDER BY RAND()

hm. выглядит конечно забавно, но.. оно действительно сработает? :)

ps: у меня сейчас нет доступа к базе, чтобы проверить.

// wbr

klalafuda ★☆☆
() автор топика
Ответ на: комментарий от Anoxemian

> Пруф: http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand

hm.. действительно, слона то я и не заметил. спасибо. похоже, что вопрос снимается :)

ps: при таком раскладе почти уверен, что PgSQL то-же умеет делать что то подобное.

// wbr

klalafuda ★☆☆
() автор топика
Ответ на: комментарий от klalafuda

>hm. выглядит конечно забавно, но.. оно действительно сработает? :)

Э... Это, как бы стандартное решение для случайной выборки.

KRoN73 ★★★★★
()
Ответ на: комментарий от Anoxemian

в 8-м постгресе работает :
SELECT * FROM content ORDER BY RANDOM()

kto_tama ★★★★★
()
Ответ на: комментарий от anonymous

>Если количество записей большое, то ORDER BY RAND() очень плохая идея

Если количество записей большое, то rand обычно теряет смысл. Случайные записи выбирают, скажем, не за 10 лет, а за последний месяц или неделю. Тогда rand опять хорошая идея :)

А по ссылке - костыли :) Которые и равномерность выборки нарушают, и в разряженном массиве плохо работают... Но тоже иногда, конечно, применимы.

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

> Если количество записей большое, то rand обычно теряет смысл. Случайные записи выбирают, скажем, не за 10 лет, а за последний месяц или неделю. Тогда rand опять хорошая идея :)

ну тут на самом деле вопрос в определении "большое". если в таблице 10ть записей, то, очевидно, это "маленькое". а если их 10k - это уже большое?

// wbr

klalafuda ★☆☆
() автор топика
Ответ на: комментарий от klalafuda

10k в таблице или 10k за последнюю неделю? :)

Хотя 10k для rand выбирается легко.

mysql> select count(*) from posts;
+----------+
| count(*) |
+----------+
|  1605416 | 
+----------+
1 row in set (0.00 sec)

mysql> select count(*) from posts where posted > unix_timestamp()-86400*7;
+----------+
| count(*) |
+----------+
|     7362 | 
+----------+
1 row in set (0.01 sec)

mysql> select id, poster, topic_id from posts where posted > unix_timestamp()-86400*7 order by rand() limit 1;
+---------+--------+----------+
| id      | poster | topic_id |
+---------+--------+----------+
| 1734332 | 510-th |    58366 | 
+---------+--------+----------+
1 row in set (0.15 sec)

mysql> select id, poster, topic_id from posts where posted > unix_timestamp()-86400*7 order by rand() limit 3;
+---------+----------+----------+
| id      | poster   | topic_id |
+---------+----------+----------+
| 1735806 | Mathieus |    55982 | 
| 1731748 | MIKLE    |    64495 | 
| 1732344 | tramp_   |    63899 | 
+---------+----------+----------+
3 rows in set (0.26 sec)

KRoN73 ★★★★★
()
Ответ на: комментарий от anonymous

>3 из 7000 за 0.26 сек - нихрена себе легко.

30 rows in set (0.59 sec) [холодноё дёргание, тупо из буфера вчерашнюю строку взял].

300 rows in set (0.15 sec) [это уже с тепла].

При этом эта же машина сейчас отрабатывает десятки юзеровских запросов в секунду, в основном из этой же таблицы: http://admin.airbase.ru/munin/airbase/airbase/index.html#mysql

Ну а пиковая загрузка, как видно оттуда же - под 200-275 запросов в скунду. Кстати, когда-то и тысячи под полторы в секунду тянуло. Вот тогда - тормозило :)

Если это тяжело - то ты не знаешь жизни на стареньких Xeon-1800*2 :)

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

KRoN73 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.