Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Optymalizacja selecta, czy to juz kres mozliwosci???
abusiek
post
Post #1





Grupa: Zarejestrowani
Postów: 89
Pomógł: 5
Dołączył: 23.10.2006
Skąd: Gda?sk

Ostrzeżenie: (0%)
-----


Witam!

Od paru godzin optymalizuje zapytanie do dwoch tabel, w jednej (t1) jest okolo 120000 rekordow w drugiej (t2) ok 2400000.
t1 jest w relacji jeden do wielu z t2, na jeden wiersz z t1 przypada okolo 30, 40 rekordow w t2.
Pytanie czy troche ponad 4s to szczyt mozliwosci mysql-a w takich przypadkach??
Go to the top of the page
+Quote Post
2 Stron V   1 2 >  
Start new topic
Odpowiedzi (1 - 19)
wookieb
post
Post #2





Grupa: Moderatorzy
Postów: 8 989
Pomógł: 1550
Dołączył: 8.08.2008
Skąd: Słupsk/Gdańsk




Jeżeli masz założone odpowiednie indexy i wszystko zoptymalizowane to raczej tak.


--------------------
Go to the top of the page
+Quote Post
abusiek
post
Post #3





Grupa: Zarejestrowani
Postów: 89
Pomógł: 5
Dołączył: 23.10.2006
Skąd: Gda?sk

Ostrzeżenie: (0%)
-----


to mam problem winksmiley.jpg

dzieki za odpowiedz smile.gif
Go to the top of the page
+Quote Post
bigZbig
post
Post #4





Grupa: Zarejestrowani
Postów: 740
Pomógł: 15
Dołączył: 23.08.2004
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Pytanie jak wygląda zapytanie ?

Ten post edytował bigZbig 19.02.2009, 15:54:35


--------------------
bigZbig (Zbigniew Heintze) | blog.heintze.pl
Go to the top of the page
+Quote Post
abusiek
post
Post #5





Grupa: Zarejestrowani
Postów: 89
Pomógł: 5
Dołączył: 23.10.2006
Skąd: Gda?sk

Ostrzeżenie: (0%)
-----


  1. SELECT DISTINCT t1.id FROM t1, t2 WHERE t1.type = 'typ' AND t1.id = t2.t1_id AND t2.isLast = 1 AND (t2.name = 'pole1' AND (ucase(t2.value) LIKE ucase('%costam%') OR ucase(t2.value) LIKE ucase('%costam%') OR ucase(t2.value) LIKE ucase('%costam%') OR ucase(t2.value) LIKE ucase('%costam%') ))


Zapytania wygladaja jak wyzej z ze warunkow po na pola value i name moze byc wiecej. indeksy sa na t1.type, t2.t1_id

Ten post edytował abusiek 19.02.2009, 16:29:12
Go to the top of the page
+Quote Post
sowiq
post
Post #6





Grupa: Zarejestrowani
Postów: 1 890
Pomógł: 339
Dołączył: 14.12.2006
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


Zapytania typu
  1. SELECT * FROM tabela1, tabela2 WHERE tabela1.id = tabela2.id
nie są dobrym pomysłem, a już na pewno nie przy takiej ilości rekordów.
Zapytanie takie działa w prosty sposób:
1. tworzy iloczyn kartezjański obu tabel (czyli każdy z każdym)
2. wybiera z tego iloczynu pary spełniające warunek
Czyli jeżeli masz dwie tabele po 1k rekordów, a warunek spełnia tylko jedna para, to i tak najpierw będzie stworzonych milion par, a dopiero wybrany jeden wynik.
Rozwiązanie - JOIN. Poczytaj, na pewno przyspieszysz działanie.

Dalej. where t1.type = 'typ' Dużo szybciej działa porównywanie typu INT niż VARCHAR. Powinieneś te typy zapisywać jako liczby, a jeżeli nie możesz tego zmienić, to nawet stwórz dodatkowe pole typu INT, załóż na niego index i wstaw wartości odpowiadające typom (jakoś to sobie ustal).


  1. ucase(t2.value) LIKE ucase('%costam%')
Jeżeli masz kodowanie bazy inne niż binarne (a powinieneś w tym przypadku), to nie ma konieczności stosować ucase(), bo wtedy baza jest nieczuła na wielkości znaków.

Tyle mi się nasunęło na obecną chwilę.

Ten post edytował sowiq 19.02.2009, 16:31:49
Go to the top of the page
+Quote Post
abusiek
post
Post #7





Grupa: Zarejestrowani
Postów: 89
Pomógł: 5
Dołączył: 23.10.2006
Skąd: Gda?sk

Ostrzeżenie: (0%)
-----


Zastosowalem sie do twoich rad i zapytanie wyglada tak

  1. SELECT DISTINCT d.id FROM d1 d INNER JOIN decF df ON d.id = df.documentId WHERE d.listing_id = '54' AND df.isLast = 1 AND ( (df.name = 'applicationDate' AND UCASE(df.value) LIKE UCASE('%adrian%') ) OR (df.name = 'automat' AND UCASE(df.value) LIKE UCASE('%adrian%') ) OR (df.name = 'date' AND UCASE(df.value) LIKE UCASE('%adrian%') ) OR (df.name = 'from' AND UCASE(df.value) LIKE UCASE('%adrian%') ) OR (df.name = 'To' AND UCASE(df.value) LIKE UCASE('%adrian%') ) OR (df.name = 'place' AND UCASE(df.value) LIKE UCASE('%adrian%') ) OR (df.name = 'point' AND UCASE(df.value) LIKE UCASE('%adrian%') ) OR (df.name = 'point1' AND UCASE(df.value) LIKE UCASE('%adrian%') ) )


Czyli dodalem kolumne rownowazna dla type z poprzedniego posta z typem int i zastosowalem inner join. Zapytanie wykonuje sie ciut szybciej ale dalej nie schodzi ponizej 4s.

To co mi pokazuje explain:

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE d ref PRIMARY,listing_id_dx listing_id_dx 5 const 30184 Using where; Using temporary
1 SIMPLE df ref document_index document_index 5 d.id 23 Using where; Distinct
Go to the top of the page
+Quote Post
patryczakowy
post
Post #8





Grupa: Zarejestrowani
Postów: 420
Pomógł: 44
Dołączył: 22.10.2008

Ostrzeżenie: (0%)
-----


a spróbuj LEFT JOIN LUB RIGHT JOIN zdaje się że ze wszystkich join one są najszybsze


--------------------
Sztuką jest widzieć to czego nie widać.
Go to the top of the page
+Quote Post
abusiek
post
Post #9





Grupa: Zarejestrowani
Postów: 89
Pomógł: 5
Dołączył: 23.10.2006
Skąd: Gda?sk

Ostrzeżenie: (0%)
-----


sa najszybsze ale mnie interesuja tylko wiersze dopasowane z obu stron wiec i left i right join odpada
Go to the top of the page
+Quote Post
patryczakowy
post
Post #10





Grupa: Zarejestrowani
Postów: 420
Pomógł: 44
Dołączył: 22.10.2008

Ostrzeżenie: (0%)
-----


ale jak okaże się szybsze to możesz puste wiersze z poziomu php wyeliminować sprawdź może gra jest warta świeczki


--------------------
Sztuką jest widzieć to czego nie widać.
Go to the top of the page
+Quote Post
abusiek
post
Post #11





Grupa: Zarejestrowani
Postów: 89
Pomógł: 5
Dołączył: 23.10.2006
Skąd: Gda?sk

Ostrzeżenie: (0%)
-----


sprawdzilem winksmiley.jpg nie ma zadnej roznicy
Go to the top of the page
+Quote Post
phpion
post
Post #12





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Ja bym problemów szukał w użyciu DISTINCT. Potrafi on znacząco spowolnić zapytanie. Dla sprawdzenia: wykonaj sobie to samo zapytanie ale bez klauzuli DISTINCT. W rezultacie otrzymasz pewnie dużo więcej rekordów ale czas wykonywania zapytania powinien być niższy od aktualnego. Rozumiem, ze DISTINCT jest Ci koniecznie potrzebne - wówczas pomyślimy co z tym fantem zrobić.
Go to the top of the page
+Quote Post
abusiek
post
Post #13





Grupa: Zarejestrowani
Postów: 89
Pomógł: 5
Dołączył: 23.10.2006
Skąd: Gda?sk

Ostrzeżenie: (0%)
-----


rzeczywiscie jest koniecznie potrzebne, ale przy zapytaniu ktore dalem wyzej tylko bez distinct przyspieszylo o jakies 0.3s, czyli nieduzo winksmiley.jpg

Z tego co sie orientuje w mysql-u to mozna przyspieszyc distinct przy pomocy loose index scan, ale w moim przypadku nie bardzo da sie go zastosowac bo trzeba by przede wszystkim zlamac normalizacje bazy no i w indexie musialalby byc kolumna value ktora jest typu text a mysql ma ograniczenia na indeksy
Go to the top of the page
+Quote Post
dr_bonzo
post
Post #14





Grupa: Przyjaciele php.pl
Postów: 5 724
Pomógł: 259
Dołączył: 13.04.2004
Skąd: N/A

Ostrzeżenie: (0%)
-----


Ja bym sie upatrywal problemow w "LIKE '%....%'" (nie skorzysta z indexow na tym polu, ale... jesli wczesniej wybierze tylko te 20-30 rekordow to nie powinien byc problem)

Wyrzuc je wszystkie i sprawdz czas.
Dodaj tylko jeden i znow sprawdz.

Ten post edytował dr_bonzo 19.02.2009, 18:47:59


--------------------
Nie lubię jednorożców.
Go to the top of the page
+Quote Post
sowiq
post
Post #15





Grupa: Zarejestrowani
Postów: 1 890
Pomógł: 339
Dołączył: 14.12.2006
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


Tak jak pisałem wyżej - pousuwaj UCASE(). MySQL nie jest wrażliwy na wielkość znaków. No chyba, że używasz kodowania binarnego, np. utf8_bin, latin2_bin itp. Ale jeżeli masz utf8_general_ci, utf8_polish_ci, czy inne bez bin w nazwie, to MySQL nie będzie rozróżniał wielkości znaków.
Sprawdź.
Go to the top of the page
+Quote Post
abusiek
post
Post #16





Grupa: Zarejestrowani
Postów: 89
Pomógł: 5
Dołączył: 23.10.2006
Skąd: Gda?sk

Ostrzeżenie: (0%)
-----


Zapytanie przeszukuje te dwie tabelki wiec uzywanie like('%%') ani ucase nie jest opcjonalne tak naprawde. mam szukac czy w value zawiera sie taka fraza i nie zwracac uwagi na wielkosc liter. Chyba nie ma na to innego sposobu....
Go to the top of the page
+Quote Post
dr_bonzo
post
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%)
-----


A mozesz dac strukture bazki + troche przykladowych rekordow (tzn. gotowiec w SQL) to bedziemy sie mogli pobawic praktycznie?


--------------------
Nie lubię jednorożców.
Go to the top of the page
+Quote Post
abusiek
post
Post #18





Grupa: Zarejestrowani
Postów: 89
Pomógł: 5
Dołączył: 23.10.2006
Skąd: Gda?sk

Ostrzeżenie: (0%)
-----


dzieki za taki duzy odzew. Danych nie moge udostepnic bo mnie pracodawca zlinczuje, znaczy poufne sa winksmiley.jpg Ale postaram sie jutro wrzucic strukture bazy i jakis skrypt ktory wypelni ja danymi. Tych danych musi byc naprawde duzo bo czasy ktore wam podaje sa przy zapytaniu w ktorym dla pierwszej tabelki pasuje ok. 30000 wierszy. Przy innych typach (po pare tysiecy wierszy jest juz duzo lepiej)... W kazdym razie dzieki za taki duzy odzew smile.gif
Go to the top of the page
+Quote Post
sowiq
post
Post #19





Grupa: Zarejestrowani
Postów: 1 890
Pomógł: 339
Dołączył: 14.12.2006
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


Cytat(abusiek @ 19.02.2009, 20:18:42 ) *
mam szukac czy w value zawiera sie taka fraza i nie zwracac uwagi na wielkosc liter.
Sorry, ale chyba nie przeczytałeś tego co napisałem. Powtórzę zatem kolejny, trzeci raz:

MySQL przy wyszukiwaniu nie zwraca uwagi na wielkość liter. Możesz dać LIKE '%coś%', a warunek będzie spełniony dla COŚ, cOś, coŚ itd.

Wyjątkiem jest binarne kodowanie tabel/pól - napisałem o tym powyżej.
Go to the top of the page
+Quote Post
yevaud
post
Post #20





Grupa: Zarejestrowani
Postów: 471
Pomógł: 89
Dołączył: 29.07.2008
Skąd: Warszawa

Ostrzeżenie: (0%)
-----


odpowiem troche po czasie bo wlasnie sam natrafilem na podobny problem.

Zakladam ze uzywasz silnika InnoDb, jesli nie to mozesz od razu czytac koniec winksmiley.jpg

zrob dodatkowa tabele na silniku MyIsam ktora bedzie miala aktualizowane dane tekstowe(te na ktorych wykonujesz zapytanie like), oraz primary identyfikator. Dane mozesz aktualizowac triggerami lub w dowolnie wybrany sposob np. procedura skladowana odpalana w cronie (zalezy od konkretnej sytuacji co ma najwiecej sensu, najmniej obciaza baze, czy wyszukiwanie ma byc na aktualnych danych itp)

na pola tekstowe mozesz wtedy zalozyc indeks Fulltext i wtedy...

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html smile.gif

edit:
Jesli chodzi o proby optymalizacji poprzez zamiane where t1.id = t2.id na rozne join to tutaj akurat taki warunek jest rownoznaczny z inner join(wtedy niewazne czy left czy right), a szybszego joina nie ma niezaleznie od tego jak go w sql zapiszemy smile.gif

edit2:
moje zapytanie wykonywalo sie srednio ~5sec
w tym momencie nie przekracza 0.01s

Ten post edytował yevaud 22.10.2009, 13:39:05
Go to the top of the page
+Quote Post

2 Stron V   1 2 >
Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 19.08.2025 - 19:59