Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Pierwsze zapytanie trwa 3 sekundy a później 0,001 :(
Forum PHP.pl > Forum > Bazy danych > MySQL
TomASS
Cześc - mam takie zapytanie:
  1.  
  2. SELECT
  3.  
  4. AVG( IF(DR.rodzaj ='CCC',
  5. ((DRP.cena1)-(DRP.rabat1+DRP.rabat2+DRP.rabat3+DRP.rabat4+DRP.rabat5)),
  6. IF(DR.rodzaj ='WWW',
  7. IF((P.flaga1 = '1' OR P.oznaczenie LIKE '%BBB%' OR P.oznaczenie LIKE '%BBB%' OR P.oznaczenie LIKE '%BBB%'),
  8. (DRP.cena1-(DRP.rabat1+DRP.rabat2)-DRP.rabat3-DRP.rabat4),
  9. (DRP.cena1-(DRP.rabat1+DRP.rabat2)-DRP.rabat3-DRP.rabat4+DRP.rabat5)),
  10. IF(P.flaga2 = '1' OR P.oznaczenie LIKE '%BBB%' OR P.oznaczenie LIKE '%BBB%' OR P.oznaczenie LIKE '%BBB%',
  11. (DRP.cena1-(DRP.rabat1+DRP.rabat2)-DRP.rabat3-DRP.rabat4-DRP.rabat5),
  12. (DRP.cena1-(DRP.rabat1+DRP.rabat2)-DRP.rabat3+DRP.rabat4-DRP.rabat5-DRP.rabat6))) )) AS Srednia
  13.  
  14. FROM
  15. cennik_pozycje AS DRP LEFT JOIN
  16. cennik AS DR ON DR.id = DRP.id_cennik LEFT JOIN
  17. miejsca_dostaw AS MD ON DRP.id_miejsce = MD.id LEFT JOIN
  18. produkty AS P ON P.id = DRP.id_produkt
  19. WHERE
  20. MD.id_klient = 5000002 AND
  21. P.id IN (100000001,100000002) AND
  22. DR.STATUS = 'aktualny' AND
  23. DR.miejsce = 'akt' AND
  24. DRP.miejsce = 'akt' AND
  25. DR.rodzaj IN('CCC','WWW','LLL');


Nic wielce podniecającego - liczenie średniej. Średnia liczy się w zależności od pola DR.rodzaj wg różnych pól (czasmi się odejmuje rabaty, czasasmi nie - w zależnosci od DR.rodzaj).
Złączeń jest kilka - od cennika, po pozycje w cenniku, w zależności od klienta oraz produktu.
Wykonuje te zapytanie około 100 razy gdzie zmienia się pole id_klient oraz P.id
  1. MD.id_klient = 5000002 AND
  2. P.id IN (100000001,100000002) AND

Problem w tym, że za pierwsyzm razem te zapytanie (z takimi parametrami jak wyżej) wykonuje się 3,5 sekundy (co przy 100 daje czas około 5-6min), a po ponownym uruchomieniu (np. po minucie) - z tymi samimi parametrami - już tylko 0,001s sad.gif

Nie wiem co zoptymalizować - indeksy są, nie jest to coś skomplikowanego. Może te IFy w AVG? Tylko jak je obejść?
mmmmmmm
Po pierwsze spróbuj się pozbyć LEFT JOINów - wydaje mi się, że nic nie zmienią.
Po drugie sprawdź z jakich indeksów MOŻESZ skorzystać i te pola daj do WHERE. Resztę staraj się filtrować w samej formule. Albo dorób indeksy. Oczywiście sprawdź EXPLAINem.
Aha, a różnice w czasach wynikają z tego, że za drugim razem bierze z CACHE,.
TomASS
Cześć,
Cytat
Po pierwsze spróbuj się pozbyć LEFT JOINów - wydaje mi się, że nic nie zmienią.

Zmieniają - musze mieć takie dane w WHERE:
  1. MD.id_klient = 5000002 AND
  2. P.id IN (100000001,100000002) AND
  3. DR.STATUS = 'aktualny' AND
  4. DR.miejsce = 'akt' AND
  5. DRP.miejsce = 'akt' AND
  6. DR.rodzaj IN('CCC','WWW','LLL');


niestety nie mogę się ich pozbyć

Cytat
Po drugie sprawdź z jakich indeksów MOŻESZ skorzystać i te pola daj do WHERE.

Mam indeksy i dokładnie z tych co korzystam w WHERE. Tabela DRP ma 2mln rekordów, inne po kilknaście tysięcy. Gdyby nie indkesy nie trwałoby to 3s sad.gif

Cytat
Oczywiście sprawdź EXPLAINem.

Zrobiłem - wskazało tylko, że poprawnie używam indeksów

Cytat
Aha, a różnice w czasach wynikają z tego, że za drugim razem bierze z CACHE,.

Używając SELECT MYSQL_NO_CASHE identyczna sytuacja - za pierwszym razem 3sekundy, za kolejnymi 0,001
mmmmmmm
Pisząc, żebyś pozbył się LEFT JOINów miałem na m,yśli zastąpienie je JOINami.
sowiq
Zrób dwie rzeczy. Po pierwsze zobacz jak długo wykonuje się zapytanie:
  1. SELECT *
  2. FROM cennik_pozycje AS DRP
  3. LEFT JOIN [...]
  4. WHERE
  5. MD.id_klient = 5000002 AND
  6. P.id IN (100000001,100000002) AND
  7. DR.STATUS = 'aktualny' AND
  8. DR.miejsce = 'akt' AND
  9. DRP.miejsce = 'akt' AND
  10. DR.rodzaj IN('CCC','WWW','LLL');


Po drugie zobacz co zwróci:

  1. EXPLAIN
  2. SELECT *
  3. FROM cennik_pozycje AS DRP
  4. LEFT JOIN [...]
  5. WHERE
  6. MD.id_klient = 5000002 AND
  7. P.id IN (100000001,100000002) AND
  8. DR.STATUS = 'aktualny' AND
  9. DR.miejsce = 'akt' AND
  10. DRP.miejsce = 'akt' AND
  11. DR.rodzaj IN('CCC','WWW','LLL');


Explain pokaże Ci brakujące indeksy i inne problemy z Twoim zapytaniem.

A co do tego, że drugie wykonanie zapytania trwa znacznie dłużej krócej - jest to całkowicie naturalne. MySQL ma swój wewnętrzny cache, który pozwala znacznie przyspieszyć kolejne wykonanie tego samego zapytania.
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-2024 Invision Power Services, Inc.