Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Optymalizacja zapytania
Forum PHP.pl > Forum > PHP
markonix
Posiadam bardzo prostą bazę w postaci ID (INT) i Data UNIX(INT).

  1.  
  2. $res = mysql_query("SELECT `time` FROM `views` WHERE `aid` = $aid AND `time` > $ago");
  3. while ($row = mysql_fetch_row($res)) {
  4. $arr[date('Y-m-d', $row[0])] += 1;
  5. }


Tabela $arr służy do generowania wykresu.
Niestety wierszy jest sporo (miliony) i skrypt raczej się wywala. Samo zapytanie wg phpmyadmin to kilka setnych sekundy tak więc prawdopodobnie problemy są ze skryptem PHP. Próbowałem przerzucić działanie na bazę:

  1. SELECT COUNT(*), FROM_UNIXTIME(`time`, '%Y-%m-%d') FROM `views` WHERE `aid` = 123 GROUP BY FROM_UNIXTIME(`time`, '%Y-%m-%d')


Ale znów sam skrypt w phpmyadmin wykonuje się ponad 10 sekund. Dodając do tego obróbkę w PHP to znów wywołanie skryptu jest na granicy możliwości.

Jakieś sugestie?
Ilware
dodaj index na kolumnie `aid` i spróbuj zmienić zapytanie na :

  1. SELECT COUNT(*), FROM_UNIXTIME(`time`, '%Y-%m-%d') AS czas FROM `views` WHERE `aid` = 123 GROUP BY czas
lukaskolista
Jezeli index nie pomoze to proponuje utworzyc jakas tabele/plik w ktorej/ym beda dane tylko i wylacznie do wykresow. Te dane powinny byc w postaci "tylko do odczytu", czyli w takim formacie, ktorego nie trzeba bedzie parsowac ani obrabiac w zaden posob. Taka tabela/plik powinna byc na bierzaco aktualizowana przez jakis skrypt w cronie ktoremu za bardzo nie zalezy na czasie.

Takie rozwiazanie sprawdzi sie jedynie w przypadku, w ktorym nie potrzeba sledzic wykresu na bierzaco i dozwolone sa opoznienia.
markonix
Indeksy były już nałożone - zapomniałem o tym wspomnieć.

lukaskolista pomysł jest w porządku tylko wykresów jest sporo.
Aktualizacja wymagana jest nie na bieżąco ale tak np. co 15 minut.
Puszczając to cronem to ok, nie ma to wpływu na usera ale szkoda mi troszkę serwera.
Jeżeli danych będzie więcej to może to niekorzystnie wpłynąć na całą stronę dlatego chciałbym to zoptymalizować u źródła.

To tylko dwie kolumny INT i myślałem, że nie będzie tak źle.

Ostatecznie zmienię od drugiej strony - utworzę 3cią kolumną "date" (RRRR-MM-DD) i przerzucę odpowiedzialność na funkcje dodającą wiersze.
Bags_Bunny
Pokaż strukturę tabeli, trochę przykładowych danych i definicje indeksów. Jeśli nie masz wiecej niż kilka milionów rekordów, to z odpowiednimi indeksami pierwsze zapytanie powinno być wystaczająco szybkie. Drugie jest marne - może jedynie wykorzystać indeks na aid. Ile rekordów zwraca baza przy pierwszym zapytaniu?

--
W zasadzie po chwili zastowienia stwierdzam, że powinieneś mieć osobną kolumnę z datą, czyli tak, jak napisałeś wcześniej. Pomogło?
markonix
  1. SELECT COUNT(*) AS `sum` , `date`
  2. FROM `views`
  3. WHERE `aid` = 25
  4. GROUP BY `date`
  5. ORDER BY `date` DESC
  6. LIMIT 0 , 14


~ Minimum 5 sekund. W każdym dniu do policzenia jest około 100 - 200 tysięcy wyświetleń.
Troszkę mało rozwojowe te zapytanie (liczba wzrośnie i będzie znowu kiszka) ale na razie do zaakceptowania.

Co ciekawe indeks nałożony na date pogarsza sytuację o 3 sekundy.

Edit.. Usunięcie indeksu z `aid` skróciło do ~ 1 sekundy.
Chyba czas przegruntować wiedzę o indeksach..
Bags_Bunny
Nic dziwnego. Indeks na jedną kolumnę powoduje pobieranie wielu przypadkowych rekordów = dodatkowe operacje dyskowe. Dodaj jeden indeks na aid i date; spróbuj też bez sortowania, choć nie powinno być ono problemem.

--
Zmieniłbym też * w count na coś zaindeksowanego - chociażby date. Nie wiem czy MySQL jest w stanie to z tą gwiażdką zoptymalizować.

--
Poczytałem i wygląda na to, że count(*) jest jednak ok.
markonix
Podwójny indeks działa bardzo dobrze - czas wykonania poniżej 1 sekundy.
Grupowanie wg daty ułatwia także wyselekcjonowanie ostatnich 14dni, w których miały miejsce wejścia.

Sortowanie jest konieczne, aby wybrać ostatnie 14 dni (potem tylko ksort to posortowania od najmniejszej daty).
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.