Mysql
 sql >> Database >  >> RDS >> Mysql

mysql:molto semplice SELECT id ORDER BY LIMIT non utilizzerà INDEX come previsto (?!)

Le ricerche nell'indice sono per valore , non per posizione . Un indice può cercare un valore 2955900, ma non lo stai chiedendo. Stai chiedendo che la query inizi a un offset della 2955900a riga nella tabella.

L'ottimizzatore non può presumere che tutti i valori della chiave primaria siano consecutivi. Quindi è abbastanza probabile che la riga 2955900 abbia un valore molto più alto di quello.

Anche se i valori della chiave primaria sono consecutivi, potresti avere una condizione WHERE che corrisponde, ad esempio, solo al 45% delle righe. In tal caso il valore id sulla riga 2955900 sarebbe modo oltre il valore id 2955900.

In altre parole, una ricerca nell'indice del valore id 2955900 non consegnerà la riga 2955900.

Quindi MySQL non può utilizzare l'indice per l'offset di un limite. È deve scansiona le righe per contarle fino a raggiungere offset+limite di righe.

MySQL ha ottimizzazioni relative a LIMIT , ma si tratta più di interrompere una scansione della tabella una volta che ha raggiunto il numero di righe da restituire. L'ottimizzatore potrebbe comunque segnalare in un piano EXPLAIN che si aspetta che potrebbe scansionare l'intera tabella.

Un frequente malinteso su FORCE INDEX è che forza l'uso di un indice. :-)In effetti, se la query non può utilizzare un indice (o se gli indici disponibili non hanno alcun vantaggio per questa query), FORCE INDEX non ha alcun effetto.

Re il tuo commento:

L'impaginazione è un flagello frequente delle applicazioni Web basate sui dati. Nonostante quanto sia comune questa funzionalità, non è facile da ottimizzare. Ecco alcuni suggerimenti:

  • Perché stai interrogando con offset 2955900? Ti aspetti davvero che gli utenti passino al setaccio così tante pagine? La maggior parte degli utenti si arrende dopo poche pagine (esattamente quante dipende dal tipo di applicazione e dai dati).

  • Riduci il numero di query. La tua funzione di impaginazione potrebbe recuperare le prime 5-10 pagine, anche se mostra solo la prima pagina all'utente. Memorizza nella cache le altre pagine, presupponendo che l'utente avanzi di alcune pagine. Solo se avanzano oltre il set di pagine memorizzate nella cache, la tua app deve eseguire un'altra query. Potresti persino memorizzare nella cache tutte e 10 le pagine in Javascript sul browser del client, quindi fare clic su "Avanti" è istantaneo per loro (almeno per quelle prime pagine).

  • Non inserire un pulsante "Ultimo" su nessuna interfaccia utente, perché le persone lo faranno per curiosità. Avviso Google ha un pulsante "Avanti" ma non un pulsante "Ultimo". Quindi l'interfaccia utente stessa scoraggia le persone dall'esecuzione di query inefficienti con offset elevati.

  • Se l'utente avanza di una pagina alla volta, utilizzare il valore id più alto restituito nella pagina precedente nella clausola WHERE della query della pagina successiva. Cioè. quanto segue fa usa l'indice, anche senza il suggerimento FORCE INDEX:

    SELECT * FROM thistable WHERE id > 544 LIMIT 20