Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [MySQL]Problem z wylosowaniem wyników
szmerak
post 12.12.2010, 07:59:58
Post #1





Grupa: Zarejestrowani
Postów: 286
Pomógł: 12
Dołączył: 23.11.2006
Skąd: WL

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


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?
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 7)
bartek124
post 12.12.2010, 08:16:10
Post #2





Grupa: Zarejestrowani
Postów: 12
Pomógł: 0
Dołączył: 15.06.2008
Skąd: Kołaczyce

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


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.


--------------------
:)
Go to the top of the page
+Quote Post
szmerak
post 12.12.2010, 09:02:31
Post #3





Grupa: Zarejestrowani
Postów: 286
Pomógł: 12
Dołączył: 23.11.2006
Skąd: WL

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


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.

Ten post edytował szmerak 12.12.2010, 10:13:11
Go to the top of the page
+Quote Post
CuteOne
post 12.12.2010, 10:28:18
Post #4





Grupa: Zarejestrowani
Postów: 2 958
Pomógł: 574
Dołączył: 23.09.2008
Skąd: wiesz, że tu jestem?

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


  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
Go to the top of the page
+Quote Post
phpion
post 13.12.2010, 15:04:48
Post #5





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




@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.
Go to the top of the page
+Quote Post
Quadina
post 14.12.2010, 14:30:18
Post #6





Grupa: Zarejestrowani
Postów: 200
Pomógł: 38
Dołączył: 1.12.2010
Skąd: Wrocław

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


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.


--------------------
Warsztat: NetBeans 7.2 Beta, PHP, MySQL, PostgreSQL, Symfony (<=1.4), Diem, Java, Sieci neuronowe
Go to the top of the page
+Quote Post
Noidea
post 14.12.2010, 18:05:25
Post #7





Grupa: Zarejestrowani
Postów: 226
Pomógł: 61
Dołączył: 20.08.2010

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


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. ...


--------------------
Go to the top of the page
+Quote Post
Quadina
post 15.12.2010, 01:16:15
Post #8





Grupa: Zarejestrowani
Postów: 200
Pomógł: 38
Dołączył: 1.12.2010
Skąd: Wrocław

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


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.


--------------------
Warsztat: NetBeans 7.2 Beta, PHP, MySQL, PostgreSQL, Symfony (<=1.4), Diem, Java, Sieci neuronowe
Go to the top of the page
+Quote Post

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

 



RSS Wersja Lo-Fi Aktualny czas: 19.07.2025 - 19:36