2010-08-16 5 views
5

Mam następujący scenariusz: W bazie danych MySQL mam dwie tabele MyISAM, jedną z 4,2 milionami wierszy i drugą z 320 milionami wierszy. Poniżej znajduje się schemat dla tabel:Powolne zapytanie MySQL z łączeniem, mimo że EXPLAIN pokazuje dobry plan

Tabela 1 (4,2 rzędy)

F1 INTEGER UNSIGNED NOT NULL PRIMARY KEY 
f2 varchar(40) 
f3 varchar(40) 
f4 varchar(40) 
f5 varchar(40) 
f6 smallint(6) 
f7 smallint(6) 
f8 varchar(40) 
f9 varchar(40) 
f10 smallint(6) 
f11 varchar(10) 
f12 tinyint(4) 
f13 smallint(6) 
f14 text 

Tabela 2 (320M rzędy)

F1 INTEGER UNSIGNED NOT NULL PRIMARY KEY 
f2 INTEGER UNSIGNED NOT NULL 

Tabela 2 znajduje się w innej bazie danych, ale używam przechowywane procedura, która zapytuje dwie tabele. Relacja między dwiema tabelami jest taka, że ​​dla Tabeli 1.F1 może być do około. 100 wierszy w tabeli2.F1 (klucz obcy), które są zgodne, a wartość dla tabeli2.f2 zostanie zwrócona dla tych dopasowanych kluczy. mam ix1 indeks (F2 (15) F3 (10)) w tabeli 1. i IX2 Index (F1, F2) oraz IX3 (F2) w Tabeli 2

Zapytania ja prowadzące są następujące:

SELECT g.F1 
FROM DB1.Table1 g 
INNER JOIN DB2.Table2 gp ON g.F1 = gp.F1 
WHERE (gp.f2 = 452677825) AND 
(g.f2 = 'A string value') LIMIT 0,56 

to zapytanie jest czasami bardzo szybko (< 1s), ale zmienia ciąg wartości g.F2 jest w porównaniu z przewodami do zapytań, które biorą nawet ponad 11, a czasem nawet 30 sekund. Nie mogę zrozumieć, dlaczego tak się dzieje. Poniżej przedstawiono dane wyjściowe instrukcji EXPLAIN dla wykonywanego SELECT.

1, 'SIMPLE', 'g', 'ref', 'PRIMARY,IX1', 'IX1', '17', 'const', 901, 'Using where' 
1, 'SIMPLE', 'gp', 'ref', 'IX3,IX2', 'IX2', '8', 'DB1.g.F1,const', 1, 'Using index' 

co wydaje się być całkiem dobrym planem wykonania. Liczba wierszy w górnym wierszu wyjaśnień wynosi najwyżej 2000, ale nie widzę powodu, dla którego powinno to potrwać dłużej niż ułamek sekundy, aby zwrócić wyniki. Uruchomiłem również profiler w zapytaniu i zauważyłem, że zapytania spędzają 99,9% czasu na etapie "Wysyłanie danych". Czy ktoś może wyjaśnić, dlaczego tak jest i co można zrobić, aby zoptymalizować zapytanie?

Dzięki z góry, Tim

+0

Czy zapytania, które działają wolniej, są również tymi, które zwracają więcej danych? –

+0

Witaj Will. Dzięki za komentarz. Wszystkie zapytania zwrócą maksymalnie 56 wierszy, ponieważ ograniczam instrukcję. Jednak z reguły im więcej wierszy znajduje się w górnym wierszu EXPLAIN, tym dłużej trwa, ale nie zawsze tak jest. – Tim

+0

Czy zwiększenie liczby znaków zawartych w f2 w IX1 w tabeli 1 ma wpływ na wydajność? W szczególności, czy zwiększenie tego do 40 poprawia wszystko w ogóle? –

Odpowiedz

1

nie jestem ekspertem w tej dziedzinie, ale oto kilka myśli:

prędkość Zapytanie trwa dłużej, gdy g.F2 zmiany z powodu buforowania. MySQL zapisze wyniki dla każdego zapytania (dopóki pamięć podręczna nie zostanie zapełniona), ale nowe zapytania będą uruchamiane w pustej pamięci podręcznej, więc będą trwały dłużej. Nie powinieneś optymalizować w oparciu o to. (Patrz How to measure accurately)

Nie mogę powiedzieć od Państwa informacji, czy tabela g lub gp ma większą swoistość (wydaje się gp?) W klauzuli where, ale może warto spróbować podzapytanie zamiast. (Patrz How to force the inner query to execute first)

chodzi profilowania, możliwe jesteś uderzenie fizycznego progu jak przekroczenie alokacji pamięci RAM (za pomocą swapu jest katastrofalne dla wydajności), które nie byłyby w sposób oczywisty z explain, czy explain jest po prostu tak w tym przypadku.

+0

Witam, Dzięki za komentarz. W tej chwili zmieniłem powyższe zapytanie, aby użyć IN zamiast łączenia, zgodnie z sugestią. Zapytanie wygląda teraz następująco: SELECT g.F1 FROM (WYBIERZ g.F1 FROM DB1.Tabela1 g WHERE (g.f2 = 'abc')) JAK GDZIE A.F1 IN (WYBIERZ gp.F1 OD DB2. Tabela 2 gp WHERE (gp.f2 = 452677825)) LIMIT 0,56 , a zapytanie jest uruchamiane o wiele szybciej (~ 1s, 2s max). Moją misją jest, jeśli to możliwe, zredukowanie tego jeszcze bardziej! – Tim

0

Jeśli możesz spróbować zmodyfikować plik my.cnf, właściwość, z którą chcesz się bawić, to key_buffer_size. Indeksy MyISAM są przechowywane w plikach .MYI, jeśli zlokalizujesz je i zwiększysz rozmiary plików (np. Ls -lh /var/lib/mysql/dbname/*.MYI) możesz z grubsza oszacować, jak duży musi być bufor klucza, aby dopasować wszystkie twoje indeksy w. Dokumenty MySQL zalecają, aby nie przekroczyć 25% pamięci systemowej.

0

Relacja między dwiema tabelami jest taka, że ​​dla Tabeli 1.F1 może być do około. 100 wiersze Table2.F1

celu wyjaśnienia, jest związek Table1.F1 i Table2.F1 jeden do jednego, jeden do wielu? Dla mnie to stwierdzenie oznacza jeden-do-wielu, ale ze schematu każde z tych pól jest kluczem podstawowym (tj. Unikalnym).

W każdym razie podejrzewam, że mundur o numerze g.f2(15) nie jest jednolity, a po uderzeniu statystycznych wyników wydajność spada odpowiednio.

Czy wyniki

SELECT f2(15) AS f2_15, COUNT(*) AS cnt 
FROM Table1 
GROUP BY f2(15) 
ORDER BY cnt DESC 

pokazać kilka istotnych odstających?