2009-12-23 6 views
6

Ho una tabella che ha una chiave esterna in una tabella che memorizza alcuni dati BLOB. Quando eseguo un join interno sui tavoli con una condizione nella tabella principale, il tipo di join va da "index" a "ALL". Vorrei evitare questo perché la mia tabella blob è dell'ordine di decine di gigabyte. Come posso evitarlo?Come evitare una scansione completa della tabella con questo join interno di base?

Ecco unirsi alla quella interna di base:

EXPLAIN SELECT m.id, b.id, b.data 
     FROM metadata m, blobstore b 
     WHERE m.fkBlob = b.id; 

1, 'SIMPLE', 'm', 'index', 'fk_blob', 'fk_blob', '4', '', 1, 'Using index' 
1, 'SIMPLE', 'b', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'blob_index.m.fkBlob', 1, '' 

Qui ho aggiungere una condizione sul tavolo principale:

EXPLAIN SELECT m.id, b.id, b.data 
     FROM metadata m, blobstore b 
     WHERE m.fkBlob = b.id AND m.start < '2009-01-01'; 
1, 'SIMPLE', 'b', 'ALL', 'PRIMARY', '', '', '', 1, '' 
1, 'SIMPLE', 'm', 'ref', 'fk_blob,index_start', 'fk_blob', '4', 'blob_index.b.id', 1, 'Using where' 

Si noti che l'ordine in cui sono elencate le tabelle è cambiato. Ora sta eseguendo una scansione completa della tabella sulla tabella blob a causa di una condizione che ho aggiunto per quanto riguarda la tabella principale.

Ecco lo schema:

DROP TABLE IF EXISTS `blob_index`.`metadata`; 
    CREATE TABLE `blob_index`.`metadata` (
     `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
     `fkBlob` int(10) unsigned NOT NULL, 
     `start` datetime NOT NULL, 
     PRIMARY KEY (`id`), 
     KEY `fk_blob` (`fkBlob`), 
     KEY `index_start` (`start`), 
     CONSTRAINT `fk_blob` FOREIGN KEY (`fkBlob`) REFERENCES `blobstore` (`id`) 
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 


    DROP TABLE IF EXISTS `blob_index`.`blobstore`; 
    CREATE TABLE `blob_index`.`blobstore` (
     `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
     `data` mediumblob NOT NULL, 
     PRIMARY KEY (`id`) 
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

risposta

3

Credo che si sta tentando questo su tavolo vuoto (perché MySQL pensa che ha bisogno di passare attraverso una fila di fare scansione completa della tabella), ciò che potrebbe influenzare i risultati di pianificazione. Quando lo farai sul tavolo reale, i risultati di EXPLAIN potrebbero variare (e in realtà sono stati diversi nel mio test).

+0

Vostro diritto, ho buttato alcuni dati lì, ho eseguito la tabella di analisi su entrambe le tabelle e ora il primo join è di tipo range sul meta-table. – Fredrick

0

Se ho letto quello che hai pubblicato, va da index a ref e da eq_ref a all.

CREATE INDEX idx_metadata USING BTREE ON `metadata` (fkBlob,start); 

Dovrei riprenderlo.

3

L'ottimizzatore ritiene che la query trarrà vantaggio dallo scambio dell'ordine di tabella (che molto probabilmente significa che le statistiche non sono aggiornate).

Si può provare ad aggiungere un indice metadata (start, fkBlob):

CREATE INDEX ix_metadata_start_blob ON metadata (start, fkBlob) 

ed eseguire ANALYZE TABLE su entrambi i tavoli.

In questo modo, l'indice su start verrà utilizzato per il filtraggio su metadata che verrà reso leader.

Si può anche forzare esplicitamente l'ordine del join:

SELECT * 
FROM metadata m 
STRAIGHT_JOIN 
     blobstore b 
ON  b.id = m.fkBlob 
WHERE m.start <= '2009-01-01' 

, anche se è di solito non è raccomandato.

0
if the index doesnot take it right use HINTS 

select /* INDEX <index_name> */ 
blah blah blah 
from ........ 
0

Nel primo esempio, MySQL utilizzato l'indice di metadati fk_blob perché era un indice di copertura - ogni colonna si è utilizzato nella query era presente nell'indice. (Questo è il significato di "usare indice".) Quella query eseguiva ancora una scansione completa, ma eseguiva la scansione di ogni riga tramite l'indice secondario anziché il primario. Non appena hai usato start, hai perso l'indice di copertura e MySQL ha calcolato che era più veloce utilizzare blobstore come indice di guida. (L'indice primario di InnoDB è integrato con l'archiviazione di riga.)

Se si desidera che MySQL continui a utilizzare un indice di metadati come indice di guida, assicurarsi che sia presente un singolo indice che sarà utile per la query. Un indice su (start, fkBlob) sarebbe il migliore per la seconda query, ma potrebbe non essere utile per altre query. Il prossimo indice migliore è quello di sostituire (fkBlob) con (fkBlob, start).Dovrai bilanciare avere troppi indici (che sono costosi da mantenere) rispetto a piani di query efficienti. Prova, prova, prova e non credere mai ciecamente a spiegare sul tuo database di sviluppo.

Problemi correlati