2013-09-06 20 views
18

Mam do czynienia z dziwnym problemem wydajności z zapytaniem mysql.mysql: dlaczego lewe dołączenie nie używa indeksu?

SELECT 
`pricemaster_products`.*, 
`products`.* 
FROM `pricemaster_products` 
LEFT JOIN `products` 
ON `pricemaster_products`.`ean` = `products`.`products_ean` 

Najwyraźniej chcę użyć lewego sprzężenia. Ale zapytanie zajmuje dużo więcej czasu niż powinno.

Próbowałem zmienić połączenie w INNER JOIN. Zapytanie jest teraz bardzo szybkie, ale wynik nie jest tym, czego potrzebuję.

Kiedyś wyjaśnić i doszedł do następującego wniosku:

Jeśli używam „LEFT JOIN” następnie wyjaśniania wyników kwerendy w ...

type: "ALL" 
possible_keys: NULL 
key: NULL 
key_len: NULL 
ref: NULL 
rows: 90.000/50.000 (the full number of the corresponding table) 

... dla obu tabel .

Gdybym użyć "INNER JOIN" Więc wyjaśnij daje:

Na stole "produkty":

Same result as above. 

Na stole "pricemaster_products":

type: "ref" 
possible_keys: "ean" 
key: ean 
key_len: 767 
ref: func 
rows: 1 
extra: using where 

Obie tabele mają indeksy ustawić na odpowiednich kolumnach. Jedynym możliwym powodem, dla którego mógłbym myśleć, że LEFT JOIN działa tak wolno, jest to, że w ogóle nie korzysta z tego indeksu. Ale dlaczego by nie?

Struktura tabeli jest następująca:

CREATE TABLE IF NOT EXISTS `pricemaster_products` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `provider` varchar(255) CHARACTER SET utf8 NOT NULL, 
    `ean` varchar(255) CHARACTER SET utf8 NOT NULL, 
    `title` varchar(255) CHARACTER SET utf8 NOT NULL, 
    `gnp` double DEFAULT NULL, 
    `vat` int(11) DEFAULT NULL, 
    `cheapest_price_with_shipping` double DEFAULT NULL, 
    `last_cheapest_price_update` int(11) DEFAULT NULL, 
    `active` tinyint(1) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id`), 
    KEY `ean` (`ean`), 
    KEY `title` (`title`), 
    KEY `gnp` (`gnp`), 
    KEY `vat` (`vat`), 
    KEY `provider` (`provider`), 
    KEY `cheapest_price_with_shipping` (`cheapest_price_with_shipping`), 
    KEY `last_cheapest_price_update` (`last_cheapest_price_update`), 
    KEY `active` (`active`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=58436 ; 

CREATE TABLE IF NOT EXISTS `products` (
    `products_id` int(11) NOT NULL AUTO_INCREMENT, 
    `products_ean` varchar(128) DEFAULT NULL, 
    `products_status` tinyint(1) NOT NULL DEFAULT '1', 
    [a lot more of fields with no connection to the query in question] 
    PRIMARY KEY (`products_id`), 
    KEY `products_status` (`products_status`), 
    KEY `products_ean` (`products_ean`), 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=105518 ; 
+0

Którą wersję MySQL masz? –

+0

Wersja MySQL to 5.1.70 – Majiy

+1

@juergend: nie, to "podaj mi wszystkie dane w lewej tabeli i wszystkie dane dostępne w prawej tabeli". myślisz o pełnym zewnętrznym złączeniu –

Odpowiedz

39

Dwie odpowiednie pola do łączenia nie mają dokładnie ten sam typ (varchar (255) z character set utf8 i varchar (128) z latin1). Ustawiłem zarówno tę samą długość, jak i zestaw znaków, a teraz zapytanie z LEFT JOIN działa zgodnie z oczekiwaniami.

+3

Święte f *** ing sh * t. Całkowicie to przeoczyłem. Dzięki. +1 –

+2

Bardzo ci pomogło, że pomogło mi znaleźć problem z jednym z moich zapytań, gdy tabela, która została utworzona niepoprawnie (przy użyciu niewłaściwego zestawu znaków) powodowała problemy. +1 –

+1

dziękuję bardzo, że miałem ten sam problem i to doprowadzało mnie do absolutnie bananów – caro

Powiązane problemy