![]() |
![]() ![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 11 Pomógł: 0 Dołączył: 29.09.2008 Ostrzeżenie: (0%) ![]() ![]() |
Witam,
mam dosc spora baze (ok. 3 mln rekordow) z firmami w ktorej pojawil mi sie problem przy zapytaniu ktore pobiera dane firmy wg. okreslonej branzy, a wyniki sortuje po polu liczbowym - 'priorytet'. Tabele mam w innoDB a czas query siega 20sekund: Oto zapytanie:
Budowa tabeli firmy:
Budowa tabeli zlaczeniowej branz:
Wynik explain zapytania pokazuje taki rezultat (niepokojacy dla tabeli firma_branza):
Czy ktos pomoze w probie ustawienia odpowiednich indeksow zeby to dzialanie zoptymalizowac ? |
|
|
![]()
Post
#2
|
|
Grupa: Zarejestrowani Postów: 341 Pomógł: 40 Dołączył: 23.06.2009 Ostrzeżenie: (0%) ![]() ![]() |
czas masz z uwagi na to ze zapytanie wymaga tabeli tymczasowej (wymuszone najpewniej przez order by)
z czystej ciekawosci sprawdź (nie testowalem zapisu) :
sprawdz czasy, wydaje mi sie ze nawet jesli dodasz order by - takie zlaczenie powino zadzialac ciut lepiej. j. |
|
|
![]()
Post
#3
|
|
Grupa: Zarejestrowani Postów: 587 Pomógł: 131 Dołączył: 8.02.2010 Ostrzeżenie: (0%) ![]() ![]() |
Witam.
Spokojnie typ pola priorytet można zmienić na ENUM. Co do samego zapytania.
Ten post edytował rocktech.pl 20.04.2012, 10:13:05 |
|
|
![]()
Post
#4
|
|
Grupa: Zarejestrowani Postów: 52 Pomógł: 0 Dołączył: 11.05.2010 Ostrzeżenie: (0%) ![]() ![]() |
Nie potrafię, odpowiedzieć jakby to można było przyspieszyć ale mam pytanie: celowo robiłeś trzy branże dla każdej firmy? A jak firma należy do czeterech branż? Dla jednej branży masz przyporządkowaną jedną a w dwóch pozostałych NULL? Ja bym to rozbił na 3 tabele choć na 100% byłoby jeszcze wolniej, choć ładniej (IMG:style_emoticons/default/smile.gif)
|
|
|
![]()
Post
#5
|
|
Grupa: Zarejestrowani Postów: 341 Pomógł: 40 Dołączył: 23.06.2009 Ostrzeżenie: (0%) ![]() ![]() |
@rocktech.pl: przeciez tabela firma nie ma takiego indexu...
@gpi: jesli chodzi o indeksy, lepiej ci zadzialaja 3 osobne indeksy na branze, niz jeden dla wszystkich (chyba ze zawsze korzystasz z pola id_branza_1) tzn chodzi mi o to, ze jeseli bedziesz szukal tylko po polu id_branza_3 - to ten index nie zostanie wykorzystany. |
|
|
![]()
Post
#6
|
|
Grupa: Zarejestrowani Postów: 1 332 Pomógł: 294 Dołączył: 12.10.2008 Skąd: Olkusz Ostrzeżenie: (0%) ![]() ![]() |
miałem napisać podobnie do @rocktech.pl... ale... dodam, iż kolejność warunków w WHERE także ma znaczenie, delikatnie ale nie znacznie przyśpieszyłbyś zmieniając kolejność warunku gdyż mniej sprawdzeń tymczasowych by zrobiło... jednak tabelą główną do złączeń powinna być ta, gdzie jest główny warunek lub gdzie są jakieś sensowne indeksy...
podsumowując to najwydajniej nie zmieniając struktury tabeli to zapytanie zaproponowane przez @rocktech.pl:
a Twoje które powinno ciutkę szybciej zadziałać:
Ten post edytował zegarek84 20.04.2012, 10:34:34 |
|
|
![]()
Post
#7
|
|
Grupa: Zarejestrowani Postów: 915 Pomógł: 210 Dołączył: 8.09.2009 Skąd: Tomaszów Lubelski/Wrocław Ostrzeżenie: (0%) ![]() ![]() |
Abstrahując od zapytania i indexów, jeżeli masz taką możliwość to możesz też stworzyć system plików tymczasowych, który będzie działał w pamięci RAM.
|
|
|
![]()
Post
#8
|
|
Grupa: Zarejestrowani Postów: 282 Pomógł: 89 Dołączył: 12.04.2011 Ostrzeżenie: (0%) ![]() ![]() |
Czym różni się LEFT JOIN od INNER JOINa? LEFT JOIN zwraca również te rekordy z lewej tabeli, dla których nie ma rekordów w prawej tabeli spełniających warunek złączenia. Wtedy pola z drugiej tabeli przyjmują wartość NULL. W przypadku zapytania ze startera wątku dodatkowo ograniczamy rekordy z prawej tabeli warunkiem id_branza_1 = 455, czyli wcale nie chcemy niczego co by było NULL.
Wniosek jest taki, że nasz LEFT JOIN przy tym warunku staje się tak naprawdę INNER JOINem i optimizer tak właśnie go przepisał, skoro pierwsza tabela w wynikach explain jest właśnie prawa. Prawdopodobnie widząc ten dość 'silny' warunek, bo w końcu porównujemy pole z jedną, konkretną, dosyć wysoką wartością optimizer spodziewał się, że szybciej będzie zacząć od tabeli firmy_branza, ograniczyć rekordy do tych, które ten warunek spełniają, po czym połączyć to z tabelą firmy, sprawdzić status i posortować to co zostanie po priorytecie. Stąd taki a nie inny plan wykonania tego zapytania. Tylko że okazuje się, że do sortowania mamy 129168 rekordów w tymczasowej tabeli, co musi być bolesne, nie ma bata, a musimy posortować wszystkie, bo przecież najwyższy priorytet może być w ostatnim rekordzie. Biorąc pod uwagę jednak stosunkowo małą liczbie rekordów, które chcemy obejrzeć - LIMIT 20, a także fakt, że są to pierwsze rekordy - OFFSET 0, możemy się spodziewać, że gdybyśmy zaczęli od tabeli firmy, znajdując po indeksie status_priorytet najwyższe priorytety z właściwym statusem i sprawdzali czy połączone rekordy z tabeli firmy_branza mają id_branza_1 = 455 (a szansa na to jest niemała, akurat dla tej właśnie wartości), to moglibyśmy szybko przerwać, po znalezieniu 20 takich rekordów. Oczywiście gdyby tego limitu nie było, albo offset byłby wysoki, albo firm z tej branży byłoby mało, wtedy oryginalny plan wykonania byłby optymalny, w tym jednak konkretnym przypadku mamy do czynienia z klasyczną sytuacją, w której optimizer wybrał złą kolejność złączenia i trzeba mu dopomóc. Podsumowując - możemy spróbować zapytania:
|
|
|
![]()
Post
#9
|
|
Grupa: Zarejestrowani Postów: 11 Pomógł: 0 Dołączył: 29.09.2008 Ostrzeżenie: (0%) ![]() ![]() |
czas masz z uwagi na to ze zapytanie wymaga tabeli tymczasowej (wymuszone najpewniej przez order by) z czystej ciekawosci sprawdź (nie testowalem zapisu) :
sprawdz czasy, wydaje mi sie ze nawet jesli dodasz order by - takie zlaczenie powino zadzialac ciut lepiej. j. Minimalnie, ale ewidentie chodzi o ten order by... to zabija moje zapytanie. Witam.
Spokojnie typ pola priorytet można zmienić na ENUM. Co do samego zapytania.
Typy pol mialem calkiem dobrze ponazywane. Pozmienialem tylko dla status, priorytet z TINYINT 1 na ENUM. Poprawa jest ale niewielka. Dziwne ze ANALYSE z pola Varchar 255 proponuje jako bardziej optymalne TINYTEXT. Czyzby wyszukiwanie w TINYTEXT bylo szybsze niz w Vatcharach ? Co do twojej propozycji zmiany zapytania USE INDEX(id_branza) wywala blad bo indeks id_branza jest na tabeli "firma_branza" a nie na "firma" Nie potrafię, odpowiedzieć jakby to można było przyspieszyć ale mam pytanie: celowo robiłeś trzy branże dla każdej firmy? A jak firma należy do czeterech branż? Dla jednej branży masz przyporządkowaną jedną a w dwóch pozostałych NULL? Ja bym to rozbił na 3 tabele choć na 100% byłoby jeszcze wolniej, choć ładniej (IMG:style_emoticons/default/smile.gif) Troche zle to interpretujesz. Tabela "firma_branza" jest tabela laczaca tabele "firma" i "branza" (ktorej nie podawalem bo zapytanie jej nie dotyczy). id_branza_1, id_branza_2, id_branza_3 oznacza strukture drzewa branz, natomiast kazdy nowy rekord w "firma_branza" oznacza zaklasyfikowanie firmy do kolejnej branzy - takich klasyfikacji moze byc wiele. @gpi: jesli chodzi o indeksy, lepiej ci zadzialaja 3 osobne indeksy na branze, niz jeden dla wszystkich (chyba ze zawsze korzystasz z pola id_branza_1) tzn chodzi mi o to, ze jeseli bedziesz szukal tylko po polu id_branza_3 - to ten index nie zostanie wykorzystany. Wlasnie zawsze podaje caly ciag branz, moge miec: WHERE id_branza_1='1' lub WHERE id_branza_1='1' AND id_branza_2='56' lub WHERE id_branza_1='1' AND id_branza_2='56' AND id_branza_3='16' nigdy samo id_branza_2, id_branza_3 |
|
|
![]()
Post
#10
|
|
Grupa: Zarejestrowani Postów: 1 332 Pomógł: 294 Dołączył: 12.10.2008 Skąd: Olkusz Ostrzeżenie: (0%) ![]() ![]() |
Minimalnie, ale ewidentie chodzi o ten order by... to zabija moje zapytanie. a na ten priorytet nie możesz nałożyć choć jakichś indeksów?? nie jestem wyspecjalizowany w bazach ale na moje oko by to optymalnie chodziło przed where jest order i dopiero po kolei są sprawdzane warunki coby optymalniej było dalej na limit... tak tylko strzelam... jeśli na prorytet nie ma indeksu to przy wyszukiwaniu musi i tak przelecieć całą tabelę i ją odpowiednio ułożyć dosłownie za każdym razem... |
|
|
![]()
Post
#11
|
|
Grupa: Zarejestrowani Postów: 11 Pomógł: 0 Dołączył: 29.09.2008 Ostrzeżenie: (0%) ![]() ![]() |
Tutaj mam najlepszy rezultat. Musze poprzerabiac moje zapytania w tym kierunku. Dzieki wielkie. |
|
|
![]()
Post
#12
|
|
Grupa: Zarejestrowani Postów: 1 590 Pomógł: 185 Dołączył: 19.04.2006 Skąd: Gdańsk Ostrzeżenie: (0%) ![]() ![]() |
Jeśli potrzebujesz tabeli firma_branza tylko po to, by wyszukać firmy z określonych branż to nie potrzebujesz w ogóle joina. Spróbuj jeszcze tak:
Pytanie istotne, to w której tabeli jest pole "priorytet", zakładam, że w "firmy" - jeśli w branżach to trzeba to dodac do podzapytania wraz z limitem i problemu w ogóle nie będzie. Jeśli trzeba sortować dużą tabelę to problem będzie nawet przy prostym select niestety. Zależy też jak duże są obie tabele. |
|
|
![]()
Post
#13
|
|
Grupa: Zarejestrowani Postów: 11 Pomógł: 0 Dołączył: 29.09.2008 Ostrzeżenie: (0%) ![]() ![]() |
Jeśli potrzebujesz tabeli firma_branza tylko po to, by wyszukać firmy z określonych branż to nie potrzebujesz w ogóle joina. Spróbuj jeszcze tak:
Pytanie istotne, to w której tabeli jest pole "priorytet", zakładam, że w "firmy" - jeśli w branżach to trzeba to dodac do podzapytania wraz z limitem i problemu w ogóle nie będzie. Jeśli trzeba sortować dużą tabelę to problem będzie nawet przy prostym select niestety. Zależy też jak duże są obie tabele. Porobilem kilka testow i w zasadzie wydajnosc powyzszego zapytania zblizona jest do tego ktory zaproponowal wczesniejszy przedmowca ze STRAIGHT_JOIN. Ale trafilem na zagadke: O ile powyzsze zapytanie smiga przyzwoicie ok. 0.3 sek, to jak dodam drugi element warunku id_branza_2 to czas wtedy wzrasta do 240 sek!!!
Generalnie sam "Select id_firma from ..." z drugim warunkiem ograniczajacym powinien szybciej zwrocic rekordy i wykonujac go samemu tak faktycznie jest. Natomiast w uzyciu z klauzula "IN" strasznie jest to nieoptymalne u mnie. |
|
|
![]()
Post
#14
|
|
Grupa: Zarejestrowani Postów: 1 332 Pomógł: 294 Dołączył: 12.10.2008 Skąd: Olkusz Ostrzeżenie: (0%) ![]() ![]() |
jak sama nazwa mówi to są podzapytania, a podzapytania w warunku WHERE mogą działać rekurencyjnie... np. mi takie cudeńko na pewnej tabeli zadziałało wyświetlając wszystkie wiersze:
a jak indeksy są pozakładane tam, gdzie nie przynoszą wymiernych korzyści (czytaj zbyt mało unikalnych wartości) to i tak niemal wszystko musi być porównane do tego dochodzą różne przeskoki w poszukiwaniu wartości w bazie... polecam link: 7 ways to convince MySQL to use the right index i to tyle w tym temacie... |
|
|
![]() ![]() |
![]() |
Aktualny czas: 5.10.2025 - 07:38 |