2013-07-23 12 views
6

Su un semplice ma molto grande tavolo InnoDB, ho un indice univoco nella colonna A e voglio ottenere un elenco di (intero) colonna B in ordine di colonna (intero) UnPerché MySQL Innodb "Creazione indice di ordinamento" quando esiste un indice univoco?

Molto semplice query, io sono sfogliare milioni di record.

SELECT B FROM hugeTable ORDER BY A LIMIT 10000 OFFSET 500000

Questa operazione richiede 10 secondi per query su un server molto veloce?

Filesort: Yes Filesort_on_disk: Yes Merge_passes: 9

Questo non ha senso per me, perché non può usare Indice A?

Spiega che mostra semplici chiavi e file non possibili.

risposta

10

Se i valori per la colonna B non sono disponibili nelle pagine indice, MySQL dovrà accedere alle pagine nella tabella sottostante. Inoltre non esiste un predicato che filtri quali righe siano prese in considerazione e ciò significa che MySQL sta vedendo che TUTTE le righe devono essere restituite. Questo potrebbe spiegare perché l'indice non viene utilizzato.

Si noti inoltre che le operazioni LIMIT vengono elaborate alla fine dell'istruzione, come quasi l'ultimo passaggio nel piano di esecuzione, con alcune eccezioni.

8.2.1.3. Optimizing LIMIT Queries http://dev.mysql.com/doc/refman/5.5/en/limit-optimization.html

ho il sospetto che la query potrebbe fare uso di un indice di copertura, ad esempio "ON hugetable (A,B)", al fine di evitare l'operazione di ordinamento.

In assenza di un indice di copertura, è possibile provare a riscrivere la query in questo modo, per vedere se questo farà uso dell'indice sulla colonna A ed evitare un'operazione di ordinamento su milioni di righe (per ottenere le prime 510.000 righe restituite in ordine):

SELECT i.B 
    FROM (SELECT j.A 
      FROM hugeTable j 
      ORDER 
      BY j.A 
      LIMIT 10000 OFFSET 500000 
     ) k 
    JOIN hugetable i 
    ON i.A = k.A 
ORDER 
    BY k.A 

ti suggerisco di fare un EXPLAIN solo su query vista in linea (alias come k), e vedere se mostra "Using index."

È probabile che la query esterna abbia ancora l'operazione "Using filesort", ma almeno sarà su solo 10.000 righe.

(NOTA: Si consiglia di provare un "ORDER BY i.A" al posto di "k.A" sulla query esterna, e vedere se questo fa la differenza.)


ADDENDUM

Non indirizzando in modo specifico la domanda, ma in termini di prestazioni di tale query, se si tratta di "sfogliare" un insieme di righe, un'altra opzione da considerare, per arrivare alla pagina "successiva" è utilizzare il valore di "A" da l'ultima riga recuperata nella query precedente come "punto di partenza" per t la prossima fila.

La query originale sembra ricevere "pagina 51" (10.000 righe per pagina, la pagina 51 sarebbe una riga da 510.001 a 520.000).

Se si dovesse anche restituire il valore di 'A' e mantenerlo per l'ultima riga.Per ottenere la pagina "successiva", la query potrebbe effettivamente essere:

SELECT i.B, k.A 
    FROM (SELECT j.A 
      FROM hugeTable j 
      WHERE j.A > $value_of_A_from_row_520000 
     -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
      LIMIT 10000 
     ) k 
    JOIN hugetable i 
    ON i.A = k.A 
    ORDER 
    BY k.A 

Se anche hai tenuto il valore di A dalla riga "prima", è possibile utilizzare che per il backup di una pagina. Ciò funzionerebbe davvero solo per inoltrare una pagina o tornare indietro di una pagina. Saltare su una pagina diversa, dovrebbe utilizzare la forma originale della query, contando le righe.