2012-04-13 23 views
19

Osservando il piano EXPLAIN di una query, come si determina dove è possibile ottimizzare meglio le ottimizzazioni?Come ottimizzare le query MySQL in base al piano EXPLAIN

Apprezzo che una delle prime cose da verificare è se vengono utilizzati buoni indici, ma oltre a ciò sono un po 'perplesso. Attraverso prove ed errori, in passato, ho scoperto che l'ordine in cui vengono condotti i join può essere una buona fonte di miglioramento, ma come si può determinare ciò guardando il piano di esecuzione?

Mentre mi piacerebbe molto avere una buona comprensione generale su come ottimizzare le query (lettura consigliata molto apprezzata!), Mi rendo anche conto che è spesso più facile discutere casi concreti che parlare in astratto. Dal momento che sto attualmente sbattere la testa contro il muro con questo, i vostri pensieri sarebbe molto apprezzato:

 
id select_type table type  possible_keys key  key_len ref     rows Extra 
1 SIMPLE  S  const PRIMARY,l,p,f4 PRIMARY   2 const      1 Using temporary 
1 SIMPLE  Q  ref  PRIMARY,S  S    2 const     204 Using index 
1 SIMPLE  V  ref  PRIMARY,n,Q  Q    5 const,db.Q.QID   6 Using where; Using index; Distinct 
1 SIMPLE  R1  ref  PRIMARY,L  L    154 const,db.V.VID   447 Using index; Distinct 
1 SIMPLE  W  eq_ref PRIMARY,w  PRIMARY   5 const,db.R.RID,const  1 Using where; Distinct 
1 SIMPLE  R2  eq_ref PRIMARY,L  PRIMARY  156 const,db.W.RID,const  1 Using where; Distinct 

Sono corretto interpretare la riga finale del piano di esecuzione come segue:

  • come è completamente abbinato alla sua chiave primaria, solo una riga di R2 deve essere recuperata per riga di output;
  • tuttavia, tali righe di output vengono quindi filtrate in base a determinati criteri applicabili a R2?

Se è così, il mio problema sta nel filtraggio che si verifica in quella fase finale. Se la condizione non provoca alcun filtraggio (ad esempio WHERE `Col_1_to_3` IN (1,2,3)), la query viene eseguita estremamente rapidamente (~ 50 ms); tuttavia, se la condizione limita le righe selezionate (WHERE `Col_1_to_3` IN (1,2)), la query impiega molto più tempo (~ 5 s). Se la restrizione è relativa a una singola corrispondenza (WHERE `Col_1_to_3` IN (1)), l'ottimizzatore suggerisce un piano di esecuzione completamente diverso (che ha un margine leggermente migliore di 5, ma ancora molto inferiore a 50 ms). Non sembra che ci sia un indice migliore che può essere usato su quella tabella (dato che usa già la chiave primaria per restituire una riga per risultato?).

Come si dovrebbero interpretare tutte queste informazioni? Ho ragione nel ritenere che, poiché tale filtraggio degli output sta avvenendo sul tavolo finale da unire, si spreca uno sforzo considerevole contro l'adesione alla tabella precedente e il filtraggio di tali file prima? In tal caso, in che modo si determina quando è necessario unire il piano di esecuzione R2?

Mentre io resistito compreso lo schema di query & per intero qui (come mi sarebbe davvero in grado di conoscere che cosa cercare, non solo essere detto la risposta), ho capito che è necessaria per far progredire la discussione:

SELECT DISTINCT 
    `Q`.`QID` 
FROM 
    `S` 
    NATURAL JOIN `Q` 
    NATURAL JOIN `V` 
    NATURAL JOIN `R` AS `R1` 
    NATURAL JOIN `W` 

    JOIN `R` AS `R2` ON (
      `R2`.`SID` = `S`.`SID` 
     AND `R2`.`RID` = `R1`.`RID` 
     AND `R2`.`VID` = `S`.`V_id` 
     AND `R2`.`Col_1_to_3` IN (1,2) -- this is where performance suffers! 
    ) 

WHERE 
    AND `S`.`SID` = @x 
    AND `W`.`WID` = @y 
; 

la definizione di tabella R è:

CREATE TABLE `R` (
    `SID` smallint(6) unsigned NOT NULL, 
    `RID` smallint(6) unsigned NOT NULL, 
    `VID` varchar(50) NOT NULL DEFAULT '', 
    `Col_1_to_3` smallint(1) DEFAULT NULL, 
    `T` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`SID`,`RID`,`VID`), 
    KEY `L` (`SID`,`VID`,`Col_1_to_3`), 
    CONSTRAINT `R_f1` FOREIGN KEY (`SID`) REFERENCES `S` (`SID`), 
    CONSTRAINT `R_f2` FOREIGN KEY (`SID`, `VID`) REFERENCES `V` (`SID`, `VID`), 
    CONSTRAINT `R_f3` FOREIGN KEY (`SID`, `VID`, `Col_1_to_3`) REFERENCES `L` (`SID`, `VID`, `LID`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 
+0

Ti dispiace mostrare anche la query? –

+0

@MarcusAdams: Non mi dispiace *, ma cosa vorresti cercare? Sento che probabilmente imparerò di più se sapessi cosa vedresti ... – eggyal

+0

Ti riferisci a col_1_to_3, ma non vedo una colonna di questo tipo nel risultato di EXPLAIN. Se riesci a formulare la domanda in modo che riguardi solo la spiegazione, in altre parole rimuovi i paragrafi che parlano della query, allora non abbiamo bisogno della query e la risposta è sì. In generale, abbiamo bisogno della query, dello schema e della spiegazione, altrimenti indovineremo. –

risposta

13

dipende da ciò che si sta andando e che cosa la query è.

Generalmente, per ogni riga in EXPLAIN che ha un Using where, è necessario averlo usando un indice (colonna possible keys e keys). Questi sono i tuoi filtri e includono WHERE e ON. Detto questo, Using index è ancora meglio. Significa che c'è un indice di copertura e MySQL può recuperare i dati direttamente dall'indice anziché visitare la riga nei dati della tabella.

Le righe in cui non è presente lo Using where e restituiscono un numero elevato di righe da esaminare.Questi stanno restituendo i valori per tutte le righe nella tabella. Non so quale sia la tua domanda, quindi non so se essere allarmato qui. Prova a filtrare il set di risultati per ridurre le dimensioni e migliorare le prestazioni.

Generalmente si dovrebbe cercare di evitare di vedere Using filesort o Using temporary, anche se questi sono solo cattivi se non li si aspetta.

Filesort di solito appare con la clausola ORDER. In genere si desidera che MySQL utilizzi un indice di copertura (Using index) in modo che le righe vengano restituite già in ordine dal server. Se non lo sono, MySQL deve ordinarli successivamente, usando filesort.

Using temporary può essere errato quando fa riferimento alle tabelle derivate perché non hanno indici. Sembra che tu abbia creato una tabella temporanea con indici, quindi qui non è male. A volte, la tua unica scelta è usare una tabella derivata, e quindi Using temporary.

+0

Grazie Marcus. Suppongo che la cosa più strana sia la differenza significativa nelle prestazioni che deriva da un filtro sul tavolo finale; quindi sembra che il problema non sia nelle "linee in cui ... restituisce un numero elevato di righe", che suggerisci di guardare? – eggyal

Problemi correlati