2012-03-14 10 views
5

Sto utilizzando la tabella "utenti" con oltre 2 milioni di record. La query è:Utilizzo indice MySQL per query ORDER BY LIMIT

SELECT * FROM users WHERE 1 ORDER BY firstname LIMIT $start,30 

colonna "nome" è indicizzata. Ottenere le prime pagine è molto veloce mentre ottenere le ultime pagine è molto lento.

Ho usato spiegare e qui sono i risultati:

per

EXPLAIN SELECT * FROM `users` WHERE 1 ORDER BY `firstname` LIMIT 10000 , 30 

sto ottenendo:

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE users index NULL firstname 194  NULL 10030 

Ma per

EXPLAIN SELECT * FROM `users` WHERE 1 ORDER BY `firstname` LIMIT 100000 , 30 

mi sto

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE users ALL  NULL NULL NULL NULL 2292912  Using filesort 

Qual è il problema?

+0

Troppi salti. –

+0

Prova a eseguire l'istruzione 'ANALYZE TABLE users' e verifica se è d'aiuto. –

risposta

3

Non si deve utilizzare il limite per accedere alla propria banca dati.

Otterrete molto meglio i risultati utilizzando query di intervallo.

SELECT * FROM users 
WHERE firstname >= last_used_name 
ORDER BY firstname 
LIMIT 30 

Dove last_used_name è uno che hai già visto (sto supponendo che si fa l'elaborazione in batch di qualche tipo). Otterrai risultati più accurati se esegui query di intervallo su una colonna con indice univoco. In questo modo non otterrai lo stesso record due volte.

Quando si esegue

LIMIT 100000 , 30 

MySQL fa essenzialmente la stessa in

LIMIT 100030 

Solo che non restituisce primi 100 migliaia. Ma li ordina e li legge.

+0

Grazie per la risposta. Sto usando questo per impaginare la lista. Ottenere last_used_name per creare un collegamento renderebbe il mio codice più difficile. Sarebbe felice di avere qualche buona soluzione – user1270172

+0

Non c'è niente come il pranzo gratis, lo sai. Ottimizzate il vostro codice o soffrite di un 'LIMIT' lento. Terrò d'occhio questo post, forse emergeranno altre soluzioni. –

0

Per le query * senza WHERE condizione MySQL spesso non utilizza alcun indice.

La seguente query dovrebbe essere molto più veloce e fare uso dell'indice:

SELECT * 
FROM (
    SELECT user_id 
    FROM users 
    WHERE 1 
    ORDER BY firstname 
    LIMIT $start, 30) ids 
JOIN users 
USING (user_id); 

user_id è la chiave primaria.