Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL]Problem z wylosowaniem wyników
Forum PHP.pl > Forum > PHP
szmerak
Mam pewien problem z wylosowaniem wyników z bazy.

  1. $podobnesql = "SELECT id, nazwa, obraz, opis FROM filmiki WHERE idkategori='$idcat' and id <> (SELECT FLOOR( MAX(id) * RAND()) FROM filmiki) and id<>'$video' LIMIT 0,3";


Próbuje wylosować 3 wyniki obok obecnie przeglądanego filmiku ale przy tym zapytaniu wyżej filmiki nonstop się powtarzają nie wiem jak to zrobić zmienna $video jest to id obecnie przeglądanego filmiku

Z góry dziękuje za pomoc

Dobra znalazłem już odpowiedź
  1. $podobnesql = "SELECT id, nazwa, obraz, nick, views FROM filmiki WHERE idkategori='$idcat' and id<>'$video' order by rand() LIMIT 0,4";


Tylko że jest drugi problem z użyciem order by rand() przy kilku set tysiącach rekordów zapytanie może się wykonywać kilkanascie sekund tak wyczytałem. A to mnie nie ustawia ponieważ nie chcę zmulać bazy danych. Zna ktoś bardziej optymalne metody?
bartek124
Wyciąg łączną liczbę filmików z bazy danych, wygeneruj dowolną liczbę z przedziału 0,$liczbafilmów i wrzuć do zapytania zamiast order by rand(),


Kod
$podobnesql = "SELECT id, nazwa, obraz, nick, views FROM filmiki WHERE idkategori='$idcat' and id<>'$video' LIMIT $losowaliczba,4";


Gdzie $losowaliczba to wygenerowana liczba.

Jaka różnica w stosunku do rand? Taka, że pierwszy filmik będzie losowy, a następne trzy, takie, jakie następują po pierwszym, zależnie od sortowania.

Troszkę więcej kombinacji, ale przy tych kilkuset tysiącach rekordów, zysk jest. Funkcja rand() musi przeszukać wszystkie rekordy z tabeli, zanim zwróci Ci te cztery pożądane. Korzystając klauzuli LIMIT, od razu mówimy, czego chcemy.
szmerak
Problem jest w tym że funkcja rand kopiuje do tymczasowej tabeli i nadaje wartości z czego wybiera jeden za długo to trwa przy większej ilości rekordów a mi zależy na optymalnym skrypcie. Twoja odpowiedź nie rozwiązuje mojego problemu ponieważ muszą to być przypadkowe rekordy niezalezne od niczego.
CuteOne
  1. $podobnesql = "SELECT DISTINCT id, nazwa, obraz, nick, views FROM filmiki WHERE idkategori='$idcat' and id<>'$video' order by rand() LIMIT 0,4";

smile.gif
phpion
@CuteOne:
Gratulacje. Powielasz ORDER BY RAND(), a do tego dodajesz DISTINCT. Brakuje jeszcze jakiegoś iloczynu kartezjańskiego i będzie wypas.

@szmerak:
Zastosuj ideę ~bartek124, lepszego rozwiązania nie znajdziesz. Jeśli chcesz otrzymać np. 3 rekordy zupełnie losowe to pobierz łączną liczbę rekordów w tabeli, a następnie wylosuj 3 liczby z przedziału 0..n (albo n-1). Następnie wykonaj 3 zapytania w stylu podanym przez ~bartek124 łącząc je w jeden zbiór wyniku poprzez UNION.
Quadina
Metoda sprawdzona jako około 10% szybsza od naturalnego losowania przez rand mimo wykonania subquery. Odpowiedź dostosowałem do przykładu wyżej:

  1. SELECT
  2. id, nazwa, obraz, nick, views
  3. FROM
  4. filmiki
  5. WHERE
  6. id IN (
  7. SELECT id FROM filmiki
  8. WHERE idkategori='$idcat' AND id<>'$video' ORDER BY RAND()
  9. LIMIT 0,3
  10. )


Dzięki temu, że tablica tymczasowa generowana przez ORDER BY RAND() posiada tylko dwie kolumny czyli id i wartość losową po której odbędzie się sortowanie zachodzi znacznie szybciej, niż dla całej przepisanej tablicy, którą trzeba posortować. Mimo, że jest to użycie subquery wyciągające losowe id dla miliona wygenerowanych przeze mnie losowych rekordów uzyskuje 10% szybszy czas wykonania.

Jednak wciąż nie jest to rozwiązanie wystarczające. Powiem tylko że wyciąganie ilości elementów i później losowanie 3 z zakresu 0 do $max jest bezsensowne niestety... Jaka pewność, że połowa elementów nie została usunięta wewnątrz? Wtedy między wyznaczonym zakresem będzie luka, która może zostać wylosowana i przekazana do bazy danych.
Noidea
Cytat
Powiem tylko że wyciąganie ilości elementów i później losowanie 3 z zakresu 0 do $max jest bezsensowne niestety... Jaka pewność, że połowa elementów nie została usunięta wewnątrz? Wtedy między wyznaczonym zakresem będzie luka, która może zostać wylosowana i przekazana do bazy danych.


Nie chodzi o losowanie liczb z zakresu MIN_ID..MAX_ID, tylko z zakresu 0..NUM_ROWS-1 (gdzie NUM_ROWS to liczba wierszy spełniających warunki) i wstawienie do zapytania:
  1. SELECT * FROM tabela WHERE warunki ORDER BY id LIMIT $wylosowana_liczba, 1
  2. UNION
  3. ...
Quadina
Cytat(Noidea @ 14.12.2010, 18:05:25 ) *
Nie chodzi o losowanie liczb z zakresu MIN_ID..MAX_ID, tylko z zakresu 0..NUM_ROWS-1 (gdzie NUM_ROWS to liczba wierszy spełniających warunki) i wstawienie do zapytania:
  1. SELECT * FROM tabela WHERE warunki ORDER BY id LIMIT $wylosowana_liczba, 1
  2. UNION
  3. ...


Wybacz, mój błąd. Zrozumiałem, że polecacie wyciąganie ostatniego ID i losowanie od 1 do tego maksa.
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.