Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> OPTYMALNE wybieranie losowych rekordów z bazy danych
Michael2318
post
Post #1





Grupa: Zarejestrowani
Postów: 651
Pomógł: 116
Dołączył: 3.06.2012
Skąd: Lędziny

Ostrzeżenie: (0%)
-----


Zastanawiam się jaki jest najoptymalniejszy sposób na wybranie 5 losowych rekordów z bazy danych? Do tej pory raczej bezmyślnie korzystałem z rand() w zapytaniu, ale ta opcja ma bardzo negatywne opinie w sieci, dlatego też zastanawiam się w jaki sposób to zrobić inaczej, a przy tym najbardziej optymalnie jak tylko się da?
Go to the top of the page
+Quote Post
c1chy
post
Post #2





Grupa: Zarejestrowani
Postów: 72
Pomógł: 16
Dołączył: 21.06.2013

Ostrzeżenie: (0%)
-----


http://jan.kneschke.de/projects/mysql/order-by-rand/
Go to the top of the page
+Quote Post
Michael2318
post
Post #3





Grupa: Zarejestrowani
Postów: 651
Pomógł: 116
Dołączył: 3.06.2012
Skąd: Lędziny

Ostrzeżenie: (0%)
-----


Cóż, używam czegoś takiego:

  1. SELECT * FROM `table` WHERE promote = 1 AND id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` WHERE promote = 1 ) ORDER BY id LIMIT 5;


ale coś jest nie tak... Mam w bazie 7 rekordów, pasujących do tego zapytania, a wymagam tylko 5 losowych. To zapytanie w rezultacie raz daje mi 3 wyniki, raz 4, raz 5, a raz jedno... Co jest nie tak ?
Go to the top of the page
+Quote Post
mmmmmmm
post
Post #4





Grupa: Zarejestrowani
Postów: 1 421
Pomógł: 310
Dołączył: 18.04.2012

Ostrzeżenie: (0%)
-----


FLOOR(Max(id)*RND()) zwrca ci jakś konkretną liczbę. I wybierasz id>= od tej liczby. Czasem nie ma ich 5

Jeśli chcesz pseudolosowo wybrać 5 rekordów bez rand, t spróbuj cegoś tkiego:
SELECT * FROM `table` WHERE promote = 1 ORDER BY crc32(concat(unix_timestamp(),id)) LIMIT 5
Go to the top of the page
+Quote Post
ctom
post
Post #5





Grupa: Zarejestrowani
Postów: 321
Pomógł: 55
Dołączył: 19.04.2009

Ostrzeżenie: (0%)
-----


zaciekawił mnie temat , bo od czasu do czasu też korzystałem z RAND bez jakiegoś szczególnego przemyślenia. Zrobiłem mały test , może ktoś ma chwilę i potwierdzi lub ... ?

test-1
Kod
$sql = SELECT * FROM tab WHERE param1 =1 ORDER BY RAND() LIMIT 5


test-2

Kod
$sql = SELECT * FROM tab WHERE param1 =1 ORDER BY crc32(concat(unix_timestamp(),id)) LIMIT 5


test-3
Kod
$sql1 = 'SELECT MAX(id) as max , MIN(id) as min FROM tab        
    
    $Rand - tablica pięcoelementowa z rand(min,max), bez duplikatów
$sql2 = SELECT * FROM tab WHERE param1 =1 AND id IN ($Rand);



Poniżej czas wykonania 100 razy danego testu na tabelach z określoną ilością rekordów

Kod
+--------------+-------------------------+------------------------+------------------------+
| tab/test     |         test-1          |          test-2        |         test-3         |
+--------------+-------------------------+------------------------+------------------------+
| 0,1 k        |    0.097609996795654    |    0.10826182365417    |    0.21252417564392    |
|   1 k        |    0.411727905273440    |    0.37512493133545    |    0.11276888847351    |
|  10 k        |    2.324110031127900    |    1.72308802604680    |    0.13337612152100    |
| 100 k        |    30.56501388549800    |    8.64563798904420    |    0.16905999183655    |    
1 500 k        |    495.1988191604600    |    38.3752229213710    |    0.17194390296936    |
+--------------+-------------------------+------------------------+------------------------+
Go to the top of the page
+Quote Post
c1chy
post
Post #6





Grupa: Zarejestrowani
Postów: 72
Pomógł: 16
Dołączył: 21.06.2013

Ostrzeżenie: (0%)
-----


Problem pojawi się dopiero gdy będziesz miał "przerwy" w ID i wylosujesz elementy nieistniejące wówczas zapytanie nie zwróci pięciu rekordów.
Go to the top of the page
+Quote Post
Damonsson
post
Post #7





Grupa: Zarejestrowani
Postów: 2 355
Pomógł: 533
Dołączył: 15.01.2010
Skąd: Bydgoszcz

Ostrzeżenie: (0%)
-----


Kiedyś poruszałem ten temat w innym wątku, twierdząc, że aktualnie ORDER BY RAND() jest równie szybkie.

ctom: Jaką wersję MySQL wykorzystałeś do testów?

U mnie zapytanie:

  1. $sql = SELECT * FROM tab WHERE param1 =1 ORDER BY RAND() LIMIT 5


Wszystkich rekordów: 350k
Czas średni na 20 powtórzeń: 0,140 sec.
Go to the top of the page
+Quote Post
ctom
post
Post #8





Grupa: Zarejestrowani
Postów: 321
Pomógł: 55
Dołączył: 19.04.2009

Ostrzeżenie: (0%)
-----


@c1chy - fakt , to całkowicie wyklucza używanie rozwiązania z test-3


Cytat(Damonsson @ 26.11.2013, 08:08:28 ) *
ctom: Jaką wersję MySQL wykorzystałeś do testów?

mysql Ver 14.14 Distrib 5.5.31, for debian-linux-gnu (x86_64) using readline 6.2 - ale to nie jest na żadnym produkcyjnym serwerze, tylko na desktopie z domyślną konfiguracją



Cytat(Damonsson @ 26.11.2013, 08:08:28 ) *
Wszystkich rekordów: 350k
Czas średni na 20 powtórzeń: 0,140 sec.


@Damonsson- to jest średni czas z 20 powtórzeń czy SUMA czasów 20 wykonań zapytania?

Ten post edytował ctom 26.11.2013, 19:20:44
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 14.09.2025 - 21:06