Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: OPTYMALNE wybieranie losowych rekordów z bazy danych
Forum PHP.pl > Forum > Bazy danych > MySQL
Michael2318
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?
Michael2318
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 ?
mmmmmmm
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
ctom
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    |
+--------------+-------------------------+------------------------+------------------------+
c1chy
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.
Damonsson
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.
ctom
@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?
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.