![]() |
![]() ![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 124 Pomógł: 1 Dołączył: 13.07.2009 Ostrzeżenie: (0%) ![]() ![]() |
Witam,
Pracuję nad pewnym serwisem internetowym (niestety nie wolno mi podawać nazwy ani adresu), który zaczyna już dość mocno zwalniać. W chwili obecnej problem stanowią dwie tabele: - tabela produktów - MyISAM, ponad 700 tyś rekordów, ponad 180 MB. - tabela ofert do produktów - MyISAM, ponad 1 125 000 rekordów, ponad 230 MB. Do rzeczy - problem stanowi już samo przeglądanie produktów.
Cytat 20 rows in set (9.70 sec) Bez SQL_CALC_FOUND_ROWS: Cytat 20 rows in set (6.63 sec) To samo zapytanie, ale bez wyciągania danych - zamiast tego COUNT(*): Cytat 20 rows in set (6.71 sec) Teraz wracając do początku: Bez "`u`.`aktywny`=1": Cytat 20 rows in set (1.86 sec) Bez "`u`.`aktywny`=1" oraz bez "ORDER BY `p`.`name` ASC": Cytat 20 rows in set (1.16 sec) Bez "`u`.`aktywny`=1" oraz bez "`o`.`cena` BETWEEN 1 AND 99999" oraz bez "ORDER BY `p`.`name` ASC": Cytat 20 rows in set (1.07 sec) Ostatnie zapytanie, ale bez SQL_CALC_FOUND_ROWS: Cytat 20 rows in set (0.00 sec) Serwis stoi na serwerze dedykowanym... Jak przyspieszyć to zapytanie? Nie mogę zrezygnować z tych warunków WHERE, ale może da radę jakoś inaczej zapytanie skonstruować? Przejście na InnoDB pomoże czy rozwiązania trzeba szukać gdzie indziej? |
|
|
![]()
Post
#2
|
|
![]() Grupa: Moderatorzy Postów: 15 467 Pomógł: 1451 Dołączył: 25.04.2005 Skąd: Szczebrzeszyn/Rzeszów ![]() |
A nie możesz po prostu wywołać dwóch zapytań? Jedno count z tymi warunkami, drugie właściwe? Myślę, że szybciej będzie.
-------------------- ![]() ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW! |
|
|
![]()
Post
#3
|
|
![]() Grupa: Moderatorzy Postów: 36 557 Pomógł: 6315 Dołączył: 27.12.2004 ![]() |
zrob z tego zapytania EXPLAIN i zobacz na czym muli.
Zapewne musisz pozakładać własciwe indexy -------------------- "Myśl, myśl, myśl..." - Kubuś Puchatek || "Manual, manual, manual..." - Kubuś Programista "Szukaj, szukaj, szukaj..." - Kubuś Odkrywca || "Debuguj, debuguj, debuguj..." - Kubuś Developer |
|
|
![]()
Post
#4
|
|
Grupa: Zarejestrowani Postów: 124 Pomógł: 1 Dołączył: 13.07.2009 Ostrzeżenie: (0%) ![]() ![]() |
Cytat("erix") A nie możesz po prostu wywołać dwóch zapytań? Jedno count z tymi warunkami, drugie właściwe? Myślę, że szybciej będzie. Cytat("Walian") To samo zapytanie, ale bez wyciągania danych - zamiast tego COUNT(*): Cytat 20 rows in set (6.71 sec) Jak widzisz jest jeszcze gorzej, już bardziej się opłaca z SQL_CALC_FOUND_ROWS. EXPLAIN EXTENDED: Cytat id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE u ALL PRIMARY NULL NULL NULL 892 Using where; Using temporary; Using filesort 1 SIMPLE o ref produkt_id,user_id,cena user_id 3 u.user_id 19 Using where 1 SIMPLE a eq_ref PRIMARY,category_id PRIMARY 4 o.produkt_id 1 Using where Próbowałem już wcześniej z różnymi indeksami, z pozbywaniem się filesort-a, nawet z FORCE INDEX, no ale nie wiem jak sobie z tym poradzić. |
|
|
![]()
Post
#5
|
|
![]() Grupa: Moderatorzy Postów: 15 467 Pomógł: 1451 Dołączył: 25.04.2005 Skąd: Szczebrzeszyn/Rzeszów ![]() |
Huh, nie zauważyłem...
Pokaż lepiej
A jeśli chodzi o rozwiązanie - musisz każdorazowo odpytywać DB? Nie myślałeś o cache po stronie klienta? (nie mylić z cache demona) -------------------- ![]() ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW! |
|
|
![]()
Post
#6
|
|
Grupa: Zarejestrowani Postów: 124 Pomógł: 1 Dołączył: 13.07.2009 Ostrzeżenie: (0%) ![]() ![]() |
Ale jak niby taki cache zrobić? Nie widzę tu sensu, skoro najmniejsza zmiana w filtrze, przejście do innej kategorii, czy wyszukiwanie wg jakieś frazy zmienia już postać i ilość wyników. Po stronie serwera też nie ma sensu bo powstanie olbrzymia ilość plików cache. Jeśli do tego uwzględnić fakt, że ciągle są dodawane lub aktualizowane produkty to liczba "kombinacji" jest olbrzymia.
Wyciąłem kolumny, które nie biorą udziału w zapytaniu. Zresztą jest ich od cholery... Wiem, wiem - tragedia... ale muszę to jakoś przyspieszyć ;/ |
|
|
![]()
Post
#7
|
|
![]() Grupa: Moderatorzy Postów: 15 467 Pomógł: 1451 Dołączył: 25.04.2005 Skąd: Szczebrzeszyn/Rzeszów ![]() |
Cytat Wyciąłem kolumny, które nie biorą udziału w zapytaniu. Zresztą jest ich od cholery... Hmm, a nie myślałeś o rozbiciu tego na wiele tabel? Np. opisy w osobnej, łączone relacją 1-1. Jeśli są kolumny typu text/varchar - przyspieszy to wyszukiwanie. -------------------- ![]() ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW! |
|
|
![]()
Post
#8
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Daj całe create table (nie usuwaj "zbędnych" kolumn) bo nie mam jak tego przetestować na bazie aby w troszkę mniejszym stopniu pobawić się z optymalizacją.
Cytat Jeśli są kolumny typu text/varchar - przyspieszy to wyszukiwanie. Nie ma to żadnego znaczenia w tym zapytaniu -------------------- |
|
|
![]()
Post
#9
|
|
Grupa: Zarejestrowani Postów: 124 Pomógł: 1 Dołączył: 13.07.2009 Ostrzeżenie: (0%) ![]() ![]() |
Gdybym projektował ten serwis od początku to tak właśnie bym zrobił bo upraszcza to również eksport danej tabeli, czy jej przywracanie.
W sumie najwięcej kolumn (39, większość to VARCHAR) jest w tabeli userów, tabele produktów i ofert akurat nie mają ich dużo. Niestety musiałbym napisać skrypt, który to wszystko rozdzieli, a potem zatrzymać serwis na czas wszystkich operacji. A nie chcę robić tego wszystkiego jeśli nie mam gwarancji, że to da cokolwiek. Tym bardziej, że dopiero przenieśliśmy się na dedyka, co zajęło masę czasu. Myślisz, że na pewno się opłaci? W sumie i tak musiałbym poczekać z tym do poniedziałku, aż wróci drugi programista. Do tego czasu szukam różnych, alternatywnych rozwiązań. EDIT: To wyżej było do erixa, spóźniłem się z postem ![]() wookieb - zaraz zapodam. Ten post edytował Walian 17.08.2010, 12:09:15 |
|
|
![]()
Post
#10
|
|
Grupa: Zarejestrowani Postów: 98 Pomógł: 0 Dołączył: 18.03.2008 Skąd: Olsztyn Ostrzeżenie: (20%) ![]() ![]() |
Sugeruję zastosowanie AJAX on szybko dłubie w danych i zwraca wyniki.
|
|
|
![]()
Post
#11
|
|
![]() Grupa: Moderatorzy Postów: 15 467 Pomógł: 1451 Dołączył: 25.04.2005 Skąd: Szczebrzeszyn/Rzeszów ![]() |
Cytat Nie ma to żadnego znaczenia w tym zapytaniu Czy ja wiem? Jeśli są kolumny różnej długości, to nie ma możliwości odczytu sekwencyjnego (paczkami o stałej długości), tylko trzeba każdorazowo tę długość sprawdzać i wtedy skakać... ~kaminskp - tiaa, tylko że w poruszanym problemie nie ma jak wykonać jakiegokolwiek JS... -------------------- ![]() ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW! |
|
|
![]()
Post
#12
|
|
Grupa: Zarejestrowani Postów: 124 Pomógł: 1 Dołączył: 13.07.2009 Ostrzeżenie: (0%) ![]() ![]() |
A teraz czas na MATRIX:
Pewnie kilka kolumn nie jest w ogóle używanych, to się je prędzej czy później wywali. |
|
|
![]()
Post
#13
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Sugeruję zastosowanie AJAX on szybko dłubie w danych i zwraca wyniki. Idź do kąta, zastanów się nad swoim postępowaniem i nie gadaj głupot. -------------------- |
|
|
![]()
Post
#14
|
|
![]() Grupa: Moderatorzy Postów: 15 467 Pomógł: 1451 Dołączył: 25.04.2005 Skąd: Szczebrzeszyn/Rzeszów ![]() |
Na próbę - przenieś kolumny varchar/text (tyle, ile się da) do osobnej tabeli, np. userMeta zostawiając pozostałe. Oczywiście nazwa użytkownika i login trzeba zostawić.
I teraz zobacz, ile czasu zajmie wyciągnięcie z tej pierwszej, z atrybutem aktywny=1. Podejrzewam, że przyspieszy. Wtedy JOIN z drugą tabelą (relacja 1-1 po np. ID użytkownika) i pokaż, jak wychodzi czas. Nie siedzę aż tak mocno w bazach, więc moje myślenie może być błędne (niech kto poprawi, jeśli tak jest), ale patrząc na logikę działania wydaje mi się całkiem sensowne. Najlepiej niech zweryfikują to fakty. ![]() -------------------- ![]() ZCE :: Pisząc PW załączaj LINK DO TEMATU i TYLKO w sprawach moderacji :: jakiś błąd - a TREŚĆ BŁĘDU? :: nie ponaglaj z odpowiedzią via PW! |
|
|
![]()
Post
#15
|
|
![]() Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Niestety MyIsam słabo spisuje się w operacjach złączenia (wynika to między innymi z tego powodu, że nie przechowuje głównego indeksu tabeli w kluczach tak jak INNODB).
Po próbie zmiany myisam na innodb złączenia odrazu zaczęły wykorzystywać klucze. Próbuję "conieco" zoptymalizować tabele i wynikami pochwale się jak tylko uda mi się coś zrobić aczkolwiek zastanów się na przyszłość czy nie lepiej przejśc na INNODB i do wyszukiwania wykorzystać sphinxa bądź inne systemy wyszukiwania (w zastępstwie FULLTEXT). Ten post edytował wookieb 17.08.2010, 12:40:00 -------------------- |
|
|
![]()
Post
#16
|
|
Grupa: Zarejestrowani Postów: 124 Pomógł: 1 Dołączył: 13.07.2009 Ostrzeżenie: (0%) ![]() ![]() |
Stworzyłem nawet nieco mniejszą tabelkę dla testu:
Niestety ZERO przyspieszenia. A nawet działa nieco wolniej, choć to może być przypadek. wookieb - ja zawsze byłem za InnoDB, ale jak wspominałem - nie ja zacząłem projektować ten serwis. Co do Sphinxa - nigdy z niego nie korzystałem, tak więc nie znam się na nim, wyczytałem jedynie mnóstwo pozytywnych opinii na jego temat, także kiedyś na pewno się nim pobawię, ale chyba nie w tym serwisie, bo raczej nie będzie na to czasu. Ten post edytował Walian 17.08.2010, 12:45:27 |
|
|
![]()
Post
#17
|
|
![]() Grupa: Przyjaciele php.pl Postów: 5 724 Pomógł: 259 Dołączył: 13.04.2004 Skąd: N/A Ostrzeżenie: (0%) ![]() ![]() |
Hmm, indeksy na kolumnach zlaczen są.
Robisz LEFT JOINA do userów, a potem WHERE user.is_active = 1. Czyli wlasciwie LEFT JOIN ci nie potrzebny - bo jesli nie znajdize usera to kolumny 'userowe' beda mialy wszedzie NULLe a NULL =?= true zawsze jest NIEspelnione. Po tej zmianie EXPLAIN dla tabeli userow uzywa u mnie klucza glownego zamiast robic full scan'a. ----- Przed Kod id select_type table type possible_keys key key_len ref rows Extra // produkty ma alias 'a' 1 SIMPLE u ALL PRIMARY NULL NULL NULL 892 Using where; Using temporary; Using filesort 1 SIMPLE o ref produkt_id,user_id,cena user_id 3 u.user_id 19 Using where 1 SIMPLE a eq_ref PRIMARY,category_id PRIMARY 4 o.produkt_id 1 Using where ![]() Kod id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE u index PRIMARY PRIMARY 4 NULL 12 Using index; Using temporary; Using filesort 1 SIMPLE o ref produkt_id,user_id,cena user_id 3 test.u.user_id 15 Using where 1 SIMPLE p eq_ref PRIMARY,category_id PRIMARY 4 test.o.produkt_id 1 Using where jako że danych mam neiwiele (180 ofert) to czasów nie jestem w stanie podać. Ten post edytował dr_bonzo 17.08.2010, 13:13:15 -------------------- Nie lubię jednorożców.
|
|
|
![]()
Post
#18
|
|
Grupa: Zarejestrowani Postów: 124 Pomógł: 1 Dołączył: 13.07.2009 Ostrzeżenie: (0%) ![]() ![]() |
Nie kumam - jeśli nie LEFT JOIN to co?
Cytat bo jesli nie znajdize usera to kolumny 'userowe' beda mialy wszedzie NULLe a NULL =?= true zawsze jest NIEspelnione. Sprawdziłem tak:
Zwróciło 0. Chyba, że źle zrozumiałem lub źle sprawdziłem. Nie wiem, co żeś za zapytanie zmajstrował, że Ci takie EXPLAIN wyszło. |
|
|
![]()
Post
#19
|
|
Grupa: Zarejestrowani Postów: 78 Pomógł: 2 Dołączył: 21.10.2006 Ostrzeżenie: (0%) ![]() ![]() |
a wiedziałeś o tym że:
rozbijane jest na:
jeżeli masz drzewko kategorii oparte na left-right lepiej będzie zastąpić to beetwenem z podaniem odpwiednich wartści roota drzewka. Ten post edytował VegetaSSJ 17.08.2010, 14:33:07 |
|
|
![]()
Post
#20
|
|
![]() Grupa: Przyjaciele php.pl Postów: 5 724 Pomógł: 259 Dołączył: 13.04.2004 Skąd: N/A Ostrzeżenie: (0%) ![]() ![]() |
Cytat Nie kumam - jeśli nie LEFT JOIN to co? To INNER JOIN (zapomnialem dopisac) i Cytat ...WHERE aktywny = NULL; o czyms zapomniales:
--- no i SQLka szukajaca
LIMIT 0,20 Ten post edytował dr_bonzo 17.08.2010, 14:39:16 -------------------- Nie lubię jednorożców.
|
|
|
![]() ![]() |
![]() |
Aktualny czas: 22.08.2025 - 09:17 |