koji » 2015.08.24 19:51

Как можно провести такую выборку? Поиск выдает решение ORDER BY RAND() однако, говорят, что это сказывается на производительности.

Gemorroj » 2015.08.24 22:49

сказывается. но если у тебя БД не 1.000.000 записей, то забей и используй order by rand. т.к. иные решения чересчур черезжопные.

koji » 2015.08.24 23:11

Gemorroj, сделал набросок через multi_query и php, но мне бы получать как-то уникальный rand. Может имеется у тебя?
так:
запрос кол-ва записей в бд;
генерация 10 чисел из этого диапазона при помощи PHP rand();
генерация в цикле 10 запросов с этими случайными числами, т.е. их подстановка;
запрос через multi_query

koji » 2015.08.25 08:11

Не знаю как производить дополнительную генерацию rand внутри if (in_array($rand, $random)) до тех пор пока не выпадет уникальное число.
Еще можно нарандить 100 чисел и пропустить их через array_unique.
Как быть, Gemorroj, пожалуйста, доведи до ума.

Код:

1
lt;?$row[0] = 20; // суммарное кол-во записей в БД$random = [];$match = 0; for ($i = 1; $i <= 10; $i++) { $rand = (string) rand(1, $row[0]); if (in_array($rand, $random)) { // если есть совпадение запускаем rand еще раз $rand = (string) rand(1, $row[0]); $match += 1; // узнать кол-во совпадений } $random[$i] = $rand; // массив уникальных чисел }echo var_dump($random) . '<br>';echo $match . '<br>';?>
koji » 2015.08.25 08:36

Какая вероятность что из 50 random чисел не окажется 10 уникальных? Этот вариант тоже подходит, но его нельзя масштабировать. Чем больше диапазон требуемых уникальных чисел тем больше потребуется генерировать случайных и медленнее будет работать.

Код:

1
2
3
4
5
6
7
8
9
10
11
12
13
$row[0] = 20; // суммарное кол-во записей в БД
 
for ($i = 1; $i <= 50; $i++)
{
$rand[] = rand(1, $row[0]);
}
 
$unique = array_unique($rand); // здесь еще бы ключи переписать последовательно: 0 1 2 3 4 5 6 7...
 
for ($i = 1; $i <= 10; $i++)
{
echo $unique[$i] . ', ';
}
Gemorroj » 2015.08.25 09:26

я так и не понял чем не подошел order by rand

koji » 2015.08.25 09:39

Gemorroj, совесть сожрет. Альтернатива в 2 минутах.. через multi_query

tipsun » 2015.08.25 11:25

koji, а нельзя сделать типа: сгенерировать 1 случайное число и ограничить кол-во записей LIMIT 10.
А чтоб не получилось так, что не хватает записи при 100 записях в базе и сгенерило случ. число 95, сделать -10 у получаемого рандомного числа.
Записи будут только идти подряд, но будут уникальными и своего рода тоже рандомными :)
- - - -
Во всех остальных случаях тебе все равно надо обращаться к базе с COUNT(), чтоб узнать текущее кол-во записей, вложить в функцию, возможно свою, чтоб получить 100% рандомных 10 чисел, снова отправить запрос в базу, вытащить запрос.
Добавлено спустя   6 минут  24 секунды:
Вот ещё на хабре пишут про оптимизацию:
- http://habrahabr.ru/post/55864/
- http://habrahabr.ru/post/54176/
- http://habrahabr.ru/post/54176/#comment_1444785

koji » 2015.08.25 11:44

tipsun, не совсем понял, что рекомендуешь на словах. Благодарю за хабра-ссылки, надо бы замерить скорость.

tipsun » 2015.08.25 11:48

koji, ну сгенерировал 1 число (выбрал 1 случайное id/запись) и далее после него цепляешь еще, 9 за ним которые.
Если записи не повторяются, то 100% уникальность гарантирована.
Но они будут идти подряд: типа 51 и цепляешь 52, 53, .., 60
Не знаю, это лишь мысль, как будет с производительностью и все такое..

koji » 2015.08.25 12:24

tipsun, а если окажется что в БД выбранное 51 это последняя запись? Хотя это неплохой вариант. Мне кажется в ссылках есть пример (из комментариев) вроде подходит, надо бы попробовать его. Но хочу доделать свой через мульти + php чтобы сравнить скорость.

tipsun » 2015.08.25 12:41

tipsun написал:

koji, а нельзя сделать типа: сгенерировать 1 случайное число и ограничить кол-во записей LIMIT 10.
А чтоб не получилось так, что не хватает записи при 100 записях в базе и сгенерило случ. число 95, сделать -10 у получаемого рандомного числа.
Записи будут только идти подряд, но будут уникальными и своего рода тоже рандомными :)

koji » 2015.08.25 16:44

tipsun, благодарю
Добавлено спустя   5 минут  31 секунду:
При 10646 записях в БД

ORDER BY RAND()
0.014

первый уникальный с последующими за ним числами  (51, 52, 53, 54 и т.д.)
0.003

т.е.

Код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$query = "
SELECT
id,
data
FROM
files AS r1
JOIN
(SELECT (RAND() * (SELECT MAX(id) FROM files)) AS ids) AS r2
WHERE
r1.id >= r2.ids
ORDER BY
r1.id ASC
LIMIT
10;
";
tipsun » 2015.08.25 17:42

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

koji » 2015.08.25 22:54

tipsun, видимо на скорую руку набросал ;) я тоже сомневался
доработал свой кусок, он отлично выбрасывает более 10 уникальных random,
выбираю по ключам в масиве $unique от 0 до 9 а остальное остается (2-5 элементов)

Код:

1
2
3
4
5
for ($i = 1; $i <= 20; $i++)
{
$rand[] = rand(1, 10646);
}
$unique = array_values(array_unique($rand));

вариант из двух: тот, что посоветовал ты и через multi_query. Последний срабатывает за 0.005. Там сгенерировать 10 запросов с выборкой WHERE id = $unique[$i] Надо бы запустить на базе побольше, тогда точно станет ясно.

tipsun » 2015.08.25 23:46

Gemorroj, что "скажешь"? Мне кажется есть ещё более крутой и оптимизированный способ.
Чисто из "спортивного" интереса сейчас ещё посидел, подумал.
Вот вроде норм вышло, но чем меньше множество, тем больше повторов и больше циклов.
+ фильтры на данные нужны, чтоб записей было более 0 и все такое крч.

Код:

1
span style="color: #0000BB"><?php$rand_zapisej = 10;$id_min = 1; // id в базе обычно начинается с 1$id_max = 10646; // получаем через базуvar_dump($rand_zapisej, randNumbs($rand_zapisej, $id_min, $id_max));function randNumbs($qty, $min, $max) { $rst = array(); while (0 < $qty) { $num = rand($min, $max); if (! $rst[$num]) { $qty--; $rst[$num] = $num; // или: $rst[$num] = null; // если null, потом foreach ($array as $key => $valueIsNull) { echo $key; } // или array_keys(randNumbs(/* args */)); } } return $rst;}
tipsun » 2015.08.26 00:00

Если кол-во записей совпадает с кол-во выводимых постов, то можно вообще сделать через: shuffle(range(1, 10));
Кстати подряд идущие записи ты прежде чем вывести можешь раскидать в массиве этой функцией: shuffle($array);

Gemorroj » 2015.08.26 09:25

tipsun ну у тебя подразумевается что дырок в очередности id в бд нету. а в реальности, записи могут отсутствовать.

koji » 2015.08.26 11:51

Gemorroj, точно, да, об этом никто не думал. ID ведь могут отсутствовать.