Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: wybieranie losowo rekordów i wydajność
Forum PHP.pl > Forum > Bazy danych > MySQL
anskellig
Witam

To mój pierwszy post tutaj, ale zdążyłem zauważyć jak przydatne jest to forum - niejednokrotnie mi pomagało. Ale do rzeczy.

1. Pytanie nr 1: Chcę pobrać losowy rekord z bazy... jak to zrobić? Robię tak:

"SELECT * FROM baza ORDER BY rand() LIMIT 1";

Ale podobno używanie rand() nie jest wydajne.
Może wydajniej byłoby tak:

$pozycja = rand(0,$ilosc_rekordow); // tutaj wcześniej trzeba by dać zapytanie zliczające rekordy
"SELECT * FROM baza LIMIT $pozycja,1";

Która opcja lepsza?

2. Pytanie nr 2: jeśli powiecie, żebym sam sprawdził co będzie wydajniejsze, to jak to zrobić?

$przed = microtime();
$query = "SELECT * FROM baza ORDER BY rand() LIMIT 1";
$result = mysql_query($query);
$po = microtime();
$czas = $po - $przed;

W ten sposób będzie dobrze?

Dzięki za sugestie.
Pozdrawiam
mike
Metoda 1. odpada, jest jak już wspomniałeś bardzo wolna. Metoda 2. jest całkiem niezłym wyjściem ale najszybsza jest ...
... a co się będę powielał smile.gif Selecting random record from MySQL database table
dr_bonzo
Fajne, fajne, ale mozna by sie czepic rozkladu prawdopodobienstwa smile.gif Czesciej beda wybierane rekordy ktore maja przed soba dziure - brakujacych IDkow smile.gif
SongoQ
@dr_bonzo Doczytaj dokladnie tu nie chodzi o ID. @mike Ciekawe przyklady podales, chociaz ten COUNT dla bardzo duzej ilosci moze roznie dzialac (wolno)
dr_bonzo
SongoQ: no rzeczywiscie, w metodzie 3. wszystko jest ok, ale pozostale maja nadal nierowny rozklad (pomijajac ofkorz 1.)
anskellig
Dzięki za odpowiedzi.

A czy ta 3 metoda (ta najszybsza) nie jest praktycznie taka sama jak moja druga? smile.gif Ja też używam w niej LIMIT $offset, 1 smile.gif

Tylko że mój $offset jest wyliczany przez rand() w PHP. Możliwe więc, że wychodzi podobnie wydajnie winksmiley.jpg W sumie ja jeszcze dokładam jedno zapytanie zliczające rekordy.
Może w ogóle niepotrzebnie się tym martwię, bo moja tabela nie będzie raczej nigdy większa niż kilka tysięcy rekordów.

A jeszcze co do tej 3 metody...
$offset_result = mysql_query( " SELECT FLOOR(RAND() * COUNT(*)) AS `offset` FROM `table` ");
Co robi to FLOOR(RAND()*COUNT(*)) ? Dlaczego rand()*count(*) ?
guitarnet.pl
nie ma co strzelac do muchy z armaty smile.gif
po prostu w jezyku ktorego uzywasz do obslugi mysql wygeneruj losowa liczbe z zakresu twoich id np min = 1, max = 9876
dla php uzyj rand() i wynik wstaw w zapytanie SQL wtedy mysql otrzyma dokladne zapytanie a funkcja rand() w php jest szybka!!

jak nie znasz min i max dla twojego ID w tabeli, cachuje je, cachowanie to podstawowa metoda w nowoczesnym programowaniu, odczytuj je np przy kazdej akcji usuwania /dodawania zawartosci tabeli i zapisuj do pliku php w postaci
<?
$min = 1;
$max= 9876;
?>

i include('./cachowany_plik.php');
dziala blyskawicznie!

oczywiscie metode cachowania dobierz do rodzaju twojegfo serwisu najbardziej optymalnie
dr_bonzo
Tja - keszowanie takiej pierdoly. Juz duzo latwiej przekleic gotowa SQLke i dostosowac do swoich nazw kolumn niz implementowac takie cache.

w sensie ze niepotrzebmie komplikuje aplikacje, i to jest raczej ta armata smile.gif
anskellig
To chyba zostanę przy tej metodzie:

$pozycja = rand(0,$ilosc_rekordow); // tutaj wcześniej trzeba by dać zapytanie zliczające rekordy
"SELECT * FROM baza LIMIT $pozycja,1";

Zamiast cachowania więc, będzie zapytanie zliczające rekordy. Dla tabeli o kilku tys. rekordów chyba nie będzie to obciążeniem. Cache'owanie wydaje mi się jednak tą armatą jak pisze poprzednik winksmiley.jpg
guitarnet.pl
ta ostatnia metoda niczym nie rozni sie od mojej, i tak musisz znac min i max id tabeli, a co jak wygenerujesz liczbe losowa spoza zakresu?

cachowanie brzmi skomplikowanie i powaznie ale to powsechnie uzywana praktyka
Kicok
Cytat
a co jak wygenerujesz liczbę losowa spoza zakresu?


No właśnie to twój sposób się na tym wykłada. Co jeśli w bazie będę miał takie dane:
Kod
+------+
|  ID  | (...)
+------+
|   1  |
|   2  |
|   5  |
|   7  |
|   8  |


a rand" title="Zobacz w manualu PHP" target="_manual zwróci mi: 3?
anskellig
Cytat(guitarnet.pl @ 8.04.2008, 14:25:12 ) *
ta ostatnia metoda niczym nie rozni sie od mojej, i tak musisz znac min i max id tabeli, a co jak wygenerujesz liczbe losowa spoza zakresu?

Jeśli zrobię tak:

$pozycja = rand(0,$ilosc_rekordow);
"SELECT * FROM baza LIMIT $pozycja,1";

To rand() nie wylosuje liczby spoza zakresu smile.gif Wszystko chyba OK. Tylko dodatkowe zapytanie zliczające ilość rekordów trzeba dać.
guitarnet.pl
racja, nie pomyslalem o braku id z zadanego zakresu, twoja metoda zdecydowanie lepsza
Sedziwoj
Cytat(dr_bonzo @ 7.04.2008, 01:03:35 ) *
SongoQ: no rzeczywiscie, w metodzie 3. wszystko jest ok, ale pozostale maja nadal nierowny rozklad (pomijajac ofkorz 1.)


Wiesz jak chcesz losowo więcej niż jeden, to wybierasz losowo pulę i z niej losowo tyle ile chcesz, wielkość puli też opiera się na zliczaniu krotek i offset więc nie ma różnicy jaki jest rozkład ID w tabeli. Co prawda rozrzut nie będzie duży takich wyborów, ale jak na razie nie widziałem lepszego. (zawsze można dodać dodatkową indeksowaną kolumnę z random i po niej sortować lol wtedy nowe krotki mogą wpadać do starych pul)
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.