оптимизация на rand()

Re: оптимизация на rand()

Надявам се поне можеш да смяташ.
Надявам се можеш да смяташ в реални условия, тук нямаш заявки от към php-то нали...

А и това не е моят вариант!

Прочети подписа ми, след което прочети какво точно съм написал като решение няколко поста по назад. ;D

Едит: А и си дал само 5 резултата, за 20 резултата сборно тайма ще е почти равен, тъй като арейнджа бави първата заявка, не лимита. 😉
 
Последно редактирано:
Re: оптимизация на rand()

Абе имам една база, на която към една таблица индекса по int поле е към 150МБ и опита показва, че на mlazarov подхода е най бързият... та на всекиму според гледната точка. Ако си на VPS-че надали ще имаш много памет за mysql и весели заявки...
Иначе имаше любопитни предложения 🙂

Пример от 3,150,000 записа.

Заявката на vaskoa
Код:
SELECT
*
FROM
the_table
JOIN
( SELECT id FROM the_table ORDER BY RAND() LIMIT 10 ) AS _random
USING (id);
Showing rows 0 - 9 (10 total, Query took 22.6256 sec)

Сам си сметни дали 10 заявки от простичките няма да са по бързички...

Простичка заявка:
Showing rows 0 - 0 (1 total, Query took 0.4521 sec) некеширан произволен ред от дискар кешираните са ~100 пъти по бързи.

Та Васко разсъждава от гледна точка на малки индекси. Естествено при толкова записи ровенето във всичките данни не е решението, което бих избрал аз поне.

За немного записи бих добавил едно поле с номер(последователни такива) и бих ползвал метода на Виктор с IN генериран от PHP. Това като по просташко решение ще свърши работа и ще е относително икономично откъм ресурси.
 
Последно редактирано:
Re: оптимизация на rand()

Та Виктор и Васко разсъждавате от гледна точка на малки индекси. Естествено при толкова записи ровенето във всичките данни не е решението, което бих избрал аз поне.

За да не бъда голословен:

Код:
SELECT SQL_NO_CACHE pid
FROM `ibf_posts`
ORDER BY RAND( )
LIMIT 30

Showing rows 0 - 29 (30 total, Query took 1.4395 sec)

Код:
SELECT SQL_NO_CACHE pid
FROM `ibf_posts`
ORDER BY RAND( )
LIMIT 5

Showing rows 0 - 4 (5 total, Query took 1.4128 sec)

За 1 резултат метода на млазаров е перфектен, в случая за 20+ не струва, както писах и по-горе, арейнджа бави първата заявка.
Т.е. Ако трябва да връща 20 резултата, първата заявка ще се изпълни пак за горе долу толкова време, но отделните заявки...
Я ми сумирайте 20 по 200 айде средно да е...

Това не е моят вариант, нито указаният по-горе!

Давам ви линк:
http://www.webmasterbg.org/showpost.php?p=65910&postcount=12
Някой изобщо някога ползвал ли е IN оператора и знае ли за какво се ползва !?

Едит: Забравих да добавя най-важното за таблицата в която тествам... Има 419,242 total записа и е с размер 480МБ. ;D
 
Последно редактирано:
Re: оптимизация на rand()

А може ли да сравниш тази заявка:

SELECT * FROM the_table ORDER BY RAND() LIMIT 10;

с тази заявка:

SELECT * FROM the_table JOIN ( SELECT id FROM the_table ORDER BY RAND() LIMIT 10 ) AS _random USING (id);

на твоята база, че ми е интересно. Според мен с малки, големи и още по-големи индекси все ще е по-бърза 2рата. Опитах и на таблица с 2 600 000 записа - 1,5 мин е първата и 10 сек е втората.

За голяма база естествено, че не е най-добрия вариант. За това написах, че е най-простия. За някой случаи обаче върши перфектна работа. Не бих сложил никога 20 заявки вместо 1, освен ако не се налага. Или пък да напиша 10 реда код ако мога да напиша 1 🙂
 
Re: оптимизация на rand()

NOT IN брои ли се? ...AND forum_id NOT IN (5,6,7,8)...
NOT IN никога не е по индекс. IN може да бъде по индекс.
Разликате е като между O👎 и O(log👎).

В примера ми горе с 3м записа O👎=3м а O(log👎)=22 (корекция 2^22, а не на 12)

Та разликата е като между 3,000,000(операции за NOT IN) и 22(операции за IN). Това последното мисля, че всички ще го разберат вече 😉
 
Последно редактирано:
Re: оптимизация на rand()

А може ли да сравниш тази заявка:

SELECT * FROM the_table ORDER BY RAND() LIMIT 10;

с тази заявка:

SELECT * FROM the_table JOIN ( SELECT id FROM the_table ORDER BY RAND() LIMIT 10 ) AS _random USING (id);

на твоята база, че ми е интересно. Според мен с малки, големи и още по-големи индекси все ще е по-бърза 2рата. Опитах и на таблица с 2 600 000 записа - 1,5 мин е първата и 10 сек е втората.

Няма алгоритмична разлика.
Код:
Showing rows 0 - 9 (10 total, Query took 26.7046 sec)
Зависи колко памет си му дал. При мен е достатъчно голям за да няма значима разлика. Също размера на самите редове в случая е малък и няма нужда от чак толкова много повече памет. С големи редове ще е по бавно, но стига да се събира в паметта нама да видиш разлика в порядъка.

За голяма база естествено, че не е най-добрия вариант. За това написах, че е най-простия. За някой случаи обаче върши перфектна работа. Не бих сложил никога 20 заявки вместо 1, освен ако не се налага. Или пък да напиша 10 реда код ако мога да напиша 1 🙂
Заявката ти е готина но неефективна за уеб. Ако правиш някви асинхронни справки си е супер издържана в теория на множествата и т.н.
 
Re: оптимизация на rand()

NOT IN никога не е по индекс. IN може да бъде по индекс.
Nikoladd, отговарях на Виктор, няма отношение към задачата.
Някой изобщо някога ползвал ли е IN оператора и знае ли за какво се ползва !?
 
Re: оптимизация на rand()

По rand() не бива да се подрежда, пише го в manual-a. Вложени кюърита и т.н. не решават проблема по никакъв начин.

Марто Лазаров е дал решението учудващо търпеливо.
 
Re: оптимизация на rand()

По rand() не бива да се подрежда, пише го в manual-a.
Естествено, ордера ще тръгне да подрежда всичко в таблицата.
И да не го пише в манюъла е близко до акъла. ;D

За натоварени сайтове с големи таблици е пределно ясно, че варианта не е добра идея заради арейнджа на цялата таблица всеки път.

Ако искам обаче повече резултати заявката си е в пъти по-бързо решение от предложеното с хилядата заявки.
^Нещо което доказах по-горе, а и Колегата Лазаров неволно доказа с качената от него лекция... ;D

Естествено никога не бих го написал по подобен начин, това, че е по-бързо, не означава че е по-леко, въобще не е...
Хамалско решение на проблема си е и ако и да е бързо товари прекалено много сървъра.

Вложени кюърита и т.н. не решават проблема по никакъв начин.
С вложено куери може да се спести отделната заявка, за вземане броя на записите в таблицата.
Не е измислено просто ей така да го има. 😉

Марто Лазаров е дал решението учудващо търпеливо.
Колегата Лазаров е дал перфектното решение, когато ти трябва 1 случаен запис от таблицата.
За повече, както в случая с нужни 20, метода е по-хамалски и от ордера по ранд!
 
Re: оптимизация на rand()

@виктор, предстои ти да откриеш любопитни неща в света на базите данни, от които ще потрепериш от възмущение. едно от тях е, че дори за 20 случайни записа марто лазаров е прав.

🙂
 
Re: оптимизация на rand()

@виктор, предстои ти да откриеш любопитни неща в света на базите данни, от които ще потрепериш от възмущение. едно от тях е, че дори за 20 случайни записа марто лазаров е прав.

Тоест искаш да кажеш, че 20 отделни заявки към всяко айди са по-добро решение,
от една заявка която селектва всичките 20 реда пак по айди със IN оператора, а дори и поотделно чрез сравнения с един OR!?

Предполагам на теб ти предстои да откриеш, че не си прочел и един от постовете ми както трябва, за да коментираш каквото и да било.

А ако си ги прочел и все още твърдиш това по-горе приложи конкретни примери, стига празни приказки и "лекции" ! ;D
 
Последно редактирано:
Re: оптимизация на rand()

Направих малко тестове смятайте си сами 🙂


Код:
mysql> select count(*) from daily;
+----------+
| count(*) |
+----------+
|  7041745 |
+----------+

Тестваме на Виктор решението /поправете ме ако съм разбрал погрешно/ :


Код:
mysql> select SQL_NO_CACHE distinct uid from daily where uid in (219, 320, 3075, 269, 250, 1911, 1312, 3075, 1808, 4122, 334) ;
+------+
| uid  |
+------+
|  250 |
|  219 |
|  269 |
|  320 |
| 1911 |
| 1808 |
|  334 |
| 1312 |
| 3075 |
| 4122 |
+------+
10 rows in set (7.02 sec)


Още веднъж
mysql> select SQL_NO_CACHE distinct uid from daily where uid in (2813, 2822, 1597, 1008, 252, 219, 269, 318, 777, 1741) ;
+------+
| uid  |
+------+
|  219 |
|  269 |
|  252 |
|  318 |
|  777 |
| 1008 |
| 1597 |
| 1741 |
| 2813 |
| 2822 |
+------+
10 rows in set (5.14 sec)

Решението на mlazarov:
Код:
mysql> select SQL_NO_CACHE *  from daily  limit 3370445,1;
+------+------------+------+---------+------+-------------+
| uid  | date       | src  | points  | suma | agent_db_id |
+------+------------+------+---------+------+-------------+
|  334 | 2007-06-06 |  976 | 0.29800 | NULL |      232138 |
+------+------------+------+---------+------+-------------+
1 row in set (0.78 sec)

mysql> select SQL_NO_CACHE *  from daily  limit 6470445,1;
+------+------------+------+---------+------+-------------+
| uid  | date       | src  | points  | suma | agent_db_id |
+------+------------+------+---------+------+-------------+
| 2668 | 2009-03-04 | 2489 | 0.07548 | NULL |      479693 |
+------+------------+------+---------+------+-------------+
1 row in set (1.64 sec)

mysql> select SQL_NO_CACHE *  from daily  limit 7173449,1;
Empty set (3.18 sec)

mysql> select SQL_NO_CACHE *  from daily  limit 10001,1;
+------+------------+------+---------+------+-------------+
| uid  | date       | src  | points  | suma | agent_db_id |
+------+------------+------+---------+------+-------------+
|    2 | 2006-08-15 |  132 | 1.34355 | NULL |       16794 |
+------+------------+------+---------+------+-------------+
[COLOR="Red"]1 row in set (0.00 sec)
[/COLOR]
mysql> select SQL_NO_CACHE *  from daily  limit 101,1;
+------+------------+------+---------+------+-------------+
| uid  | date       | src  | points  | suma | agent_db_id |
+------+------------+------+---------+------+-------------+
|    2 | 2005-09-10 |    2 | 1.11067 | NULL |          23 |
+------+------------+------+---------+------+-------------+
[COLOR="Red"]1 row in set (0.00 sec)
[/COLOR]
mysql> select SQL_NO_CACHE *  from daily  limit 7000000,1;
+------+------------+------+---------+------+-------------+
| uid  | date       | src  | points  | suma | agent_db_id |
+------+------------+------+---------+------+-------------+
| 5043 | 2011-05-01 | 3031 | 0.04032 | NULL |      619243 |
+------+------------+------+---------+------+-------------+
[COLOR="Red"]1 row in set (7.43 sec)
[/COLOR]
 

Back
Горе