Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL][PHP] ORDER BY RAND() - optymalizacja
Forum PHP.pl > Forum > Przedszkole
boro11
Witam!
Mam kod, który aktualizuje mi dane na stronie ale wykonuje się on dosyć długo ze względu na złożoność operacji jaką musi wykonać. Postanowiłem podzielić proces na pare razy przy użyciu ORDER BY RAND() i LIMIT. Strona działa dwa razy szybciej, ale gdzie nie spojrzę ORDER BY RAND() jest krytykowane z każdej strony. W normalnym zapytaniu aktualizowane są dane około 150 elementów, przy rand dałem limit 25.
Drugą sprawę jest, że nie do końca rozumiem zapis tego kodu, dodałem komentarze tam gdzie wiem co się dzieję, a tam gdzie nie mam nadzieje że mi ktoś wyjaśni wtedy może będę miał możliwośc zrobienia czego samemu.

Kod:

  1. $sites = array();
  2. $limits = array();
  3. $count = array();
  4. //Pobieranie listy obiektów do aktualizacji
  5. $zap=array(1 => 'SELECT',2 => 'nazwa, limits',3 => 'FROM',4 => 'test_site', 5 => 'ORDER BY RAND() LIMIT 25');
  6. $query = $db->zap($zap);
  7.  
  8. while ($row = mysql_fetch_array($query))
  9. {
  10. //Podejrzewam, że słuzy do zliczania, ale nie wiem jak to się odbywa - ktoś mógłby mi wyjaśnić. Jeśli nie do zliczania to do czego??
  11. $sites [$row['nazwa']] = $row['nazwa'];
  12. $limits [$row['nazwa']] = $row['limits'];
  13. $count [$row['nazwa']] = 0;
  14. }
  15.  
  16. $zap2=array(1 => 'SELECT',2 => 'site',3 => 'FROM',4 => 'test_sites',5 => 'WHERE ((status = "Approved") OR (status = "Pending"))');
  17. $quer = $db->zap($zap2);
  18. while ($row2 = mysql_fetch_array($quer))
  19. {
  20. //Co sprawdza ten zapis?
  21. if (in_array($row2['site'],$sites)) $count[$row2['site']]++;
  22.  
  23. if (($count[$row2['site']] > $limits[$row2['site']]) && ($limits[$row2['site']] != '~') && ($limits[$row2['site']]!='') && ($limits[$row2['site']]!='0'))
  24. {
  25. //Przenosi obiek do kategorii LIMITED jeśli jest spełniony warunek powyżej tj. limit został wyczerpany np. 100/100
  26. $zap3=array(1 => 'UPDATE',2 => 'test_site',3 => 'SET',4 => 'status="LIMITED"',5 => 'WHERE ((nazwa="'.$row2['site'].'") AND (status<>"SCAM"))');
  27. $db->zap($zap3);
  28. }
  29. }
  30. //Aktualizuje licznik, który znajduje się w polu "refkow" do postaci ZZ/LL, gdzie ZZ - to zapisani, a LL - to limit
  31. $zap=array(1 => 'SELECT',2 => 'nazwa, limits',3 => 'FROM',4 => 'test_site');
  32. $query2 = $db->zap($zap);
  33. while ($row2 = mysql_fetch_array($query2))
  34. {
  35. if (isset($count[$row2['nazwa']])) $put = $count[$row2['nazwa']].'/'.$row2['limits'];
  36. else $put = '0/'.$row2['limits'];
  37. $zap=array(1 => 'UPDATE',2 => 'test_site',3 => 'SET',4 => 'refkow = "'.$put.'"',5 => 'WHERE nazwa="'.$row2['nazwa'].'"');
  38. $db->zap($zap);
  39. }


Struktura w bazie danych oraz nałożone indeksy:


test_site(lista obiektów do których można się zapisać):



test_sites(tutaj znajduję się liczone zapisy):




Crozin
Nie analizowałem Twojego kodu (za wcześnie :]), ale:
1. Jeżeli pula rekordów, które chcesz wymieszać (ORDER BY RAND()) to zaledwie 150, nie masz się czego obawiać - skorzystanie z tej konstrukcji nie jest niczym złym, prawdopodobnie jedno z szybszych rozwiązań i pod względem czasu i wydajności.
2. Na pierwszy rzut oka, masz tam kilka zagnieżdżonych pętli, w których wykonują się zapytania - zapewne ilość generowanych zapytań leci w tysiącach jak nie dziesiątkach tysięcy. Podaj swoją strukturę bazy oraz jaką operację chcesz wykonać bo wygląda na to, że chwili obecnej robisz to źle.
boro11
Przerobiłem kod i udało mi się go zrobić porządnie (mam nadzieje) i o dziwi udało mi się go zamknąć w takim kodzie:

  1. $zap=array(1 => 'SELECT',2 => 'nazwa,limits,refkow',3 => 'FROM',4 => 'test_site');
  2. $query = $db->zap($zap);
  3. while ($row = mysql_fetch_array($query))
  4. {
  5. if (($row['refkow'] >= $row['limits']) && ($row['limits'] != '~') && ($row['limits']!='') && ($row['limits']!='0'))
  6. {
  7. $zap3=array(1 => 'UPDATE',2 => 'test_site',3 => 'SET',4 => 'status="LIMITED"',5 => 'WHERE ((nazwa="'.$row['nazwa'].'") AND (status<>"SCAM"))');
  8. $db->zap($zap3);
  9. }
  10. }


Postanowiłem skorzystać z tego, że mam dwa pola ilość zapisanych i limit smile.gif
Nie wiem czemu wcześniej programista mi tego nie zrobił i wymyślił taki skompilowany system, który zliczał za każdym razem od nowa ilość zapisanych. Nie wiem jaki magiczny wpływ ma to forum, ale już sami napisanie tematu pomaga smile.gif

Dziękuję za informację odnośnie rand smile.gif

Pozostało jeszcze jedno pytanie, czy powinienem jakoś zmodyfikować istniejące indeksy? Struktura wraz z obecnymi indeksami jest podana na scrennach w pierwszym poście.
Crozin
1. Wykonaj zapytanie EXPLAIN SELECT ... Twojego zapytania - zobaczysz, jak wygląda jego obsługa przez bazę danych.
2. Jeżeli korzystasz z silnika InnoDB cały kod powinieneś objąć transakcją. Nie dość, że zapewni to spójność danych to dodatkowo przyspieszy cały kod.
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.