2013-09-06 7 views
18

Sto affrontando uno strano problema di prestazioni con una query mysql.mysql: perché left join non usa un indice?

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

Desidero utilizzare esplicitamente un join sinistro. Ma la query richiede molto più tempo di quanto dovrebbe.

Ho provato a modificare il join in UN INTERNO INNER. La query ora è molto veloce, ma il risultato non è quello di cui ho bisogno.

Ho usato spiegare e sono giunti alla seguente conclusione:

Se io uso un "LEFT JOIN", quindi un EXPLAIN dei risultati della query in ...

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

... per entrambe le tabelle .

Se uso un "INNER JOIN" Poi spiega dà:

per la tabella "prodotti":

Same result as above. 

per la tabella "pricemaster_products":

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

Entrambe le tabelle hanno indici impostato sulle colonne pertinenti. L'unica ragione possibile per cui LEFT JOIN è così lento è che non usa affatto l'indice. Ma perché non dovrebbe?

La struttura della tabella è il seguente:

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

Quale versione di MySQL hai? –

+0

La versione di MySQL è 5.1.70 – Majiy

+1

@juergend: no, è "dati tutti i dati nella tabella di sinistra e tutti i dati disponibili nella tabella giusta". stai pensando a un join esterno completo –

risposta

39

I due campi rilevanti per il join non hanno esattamente lo stesso tipo (varchar (255) con CHARACTER SET utf8 e varchar (128) con latin1). Ho impostato sia la stessa lunghezza che il set di caratteri, e ora la query con LEFT JOIN funziona come previsto.

+3

Santo f *** ing sh * t. Stavo trascurando completamente questa cosa. Grazie. +1 –

+2

Grazie per avermi aiutato a trovare un problema con una delle mie query in cui una tabella creata in modo errato (utilizzando il set di caratteri errato) stava creando problemi. +1 –

+1

grazie mille ho avuto questo stesso problema e mi stava guidando assolutamente banane – caro