Prima di arrivare alla tua richiesta specifica, è importante capire come funziona un indice.
Con le statistiche appropriate, questa query:
select * from foo where bar = 'bar'
... potrà utilizzare un indice su foo(bar)
se è selettiva. Ciò significa che se bar = 'bar'
equivale a selezionare la maggior parte delle righe della tabella, sarà più veloce leggere semplicemente la tabella ed eliminare le righe che non si applicano. Al contrario, se bar = 'bar'
significa solo selezionare una manciata di righe, leggere l'indice ha senso.
Supponiamo ora gettare in una clausola ordine e che hai indici su ciascuno dei foo(bar)
e foo(baz)
:
select * from foo where bar = 'bar' order by baz
Se bar = 'bar'
è molto selettivo, è a buon mercato per afferrare tutte le righe che soddisfano, e per ordinare loro in memoria. Se non è affatto selettivo, l'indice su foo(baz)
ha poco senso perché si recupera comunque l'intera tabella: utilizzarlo significherebbe andare avanti e indietro sulle pagine del disco per leggere le righe in ordine, il che è molto costoso.
Toss in una clausola limite, tuttavia, e foo(baz)
potrebbe improvvisamente avere senso:
select * from foo where bar = 'bar' order by baz limit 10
Se bar = 'bar'
è molto selettivo, è ancora una buona opzione. Se non è affatto selettivo, troverai rapidamente 10 righe corrispondenti scansionando l'indice su foo(baz)
- potresti leggere 10 righe o 50, ma ne troverai presto dieci buone.
Supponiamo che quest'ultima query con indici su foo(bar, baz)
e foo(baz, bar)
invece. Gli indici vengono letti da sinistra a destra. Uno ha un buon senso per questa potenziale domanda, l'altro potrebbe non produrne affatto. Pensare a loro in questo modo:
bar baz baz bar
--------- ---------
bad aaa aaa bad
bad bbb aaa bar
bar aaa bbb bad
bar bbb bbb bar
Come si può vedere, l'indice foo(bar, baz)
permette di iniziare a leggere a ('bar', 'aaa')
e recupero le righe in ordine da quel punto in avanti.
L'indice su foo(baz, bar)
, al contrario, restituisce righe ordinate per baz
indipendentemente da ciò che potrebbe contenere bar
. Se bar = 'bar'
non è affatto selettivo come criterio, si eseguirà rapidamente le righe corrispondenti per la query, nel qual caso ha senso utilizzarlo. Se è molto selettivo, potresti finire per iterare migliaia di righe di righe prima di trovare una corrispondenza sufficiente a corrispondere a bar = 'bar'
- potrebbe comunque essere una buona opzione, ma è altrettanto ottimale.
Con quello che è indirizzato, torniamo alla tua richiesta originale ...
Devi iscriverti articoli con le categorie, per filtrare gli articoli che si trovano in una particolare categoria, con più di un commento, che aren' t cancellato, quindi li ordina in base alla data, quindi ne prende una manciata.
Suppongo che la maggior parte degli articoli non vengano eliminati, quindi un indice su tali criteri non sarà molto utile: rallenterà solo le scritture e la pianificazione delle query.
Suppongo che la maggior parte degli articoli abbia un commento o più, quindi anche questo non sarà selettivo. Cioè non c'è nemmeno bisogno di indicizzarlo.
Senza il filtro di categoria, le opzioni dell'indice sono ragionevolmente evidenti: articles(last_updated)
; possibilmente con la colonna conteggio dei commenti a destra e il flag eliminato a sinistra.
Con il filtro di categoria, tutto dipende ...
Se il filtro di categoria è molto selettivo, in realtà rende molto buon senso per selezionare tutte le righe che si trovano in tale categoria, ordinarli in memoria, e raccogliere le prime file corrispondenti.
Se il filtro di categoria non è affatto selettiva e produce quasi l'articolo, l'indice articles(last_update)
ha un senso: le righe sono validi in tutto il luogo, in modo da leggere righe in ordine fino a trovare abbastanza che partita e voilà.
Nel caso più generale, è solo vagamente selettivo. Per quanto ne so, le statistiche raccolte non esaminano molto le correlazioni. Pertanto, il pianificatore non ha un buon modo di stimare se troverà articoli con la categoria giusta abbastanza veloce da meritare la lettura del secondo indice. Unire e ordinare in memoria di solito costa meno, quindi il pianificatore va con quello.
In ogni caso, hai due opzioni per forzare l'uso di un indice.
Uno è quello di riconoscere che il pianificatore query non è perfetto e di utilizzare un suggerimento:
http://dev.mysql.com/doc/refman/5.5/en/index-hints.html
essere cauti, però, perché a volte il progettista è in realtà corretto nel non voler utilizzare l'indice si' mi piace o vice versione. Inoltre, potrebbe diventare corretto in una versione futura di MySQL, quindi tienilo a mente man mano che mantieni il tuo codice nel corso degli anni.
Modifica: STRAIGHT_JOIN
, come segnala anche DRap, con avvertimenti simili.
L'altro consiste nel mantenere una colonna aggiuntiva per contrassegnare gli articoli selezionati di frequente (ad esempio un campo tinyint, impostato su 1 quando appartengono alla categoria specifica), quindi aggiungere un indice su es. articles(cat_78, last_updated)
. Mantenerlo utilizzando un trigger e lo farai.
il tuo shcema non corrisponde alla query o al piano. http://sqlfiddle.com/#!9/bccd7/2. – Jodrell
inizia specificando http://sqlfiddle.com/#!9/ bccd7/5 – Jodrell
fiddle forse più utile http://sqlfiddle.com/#!9/bccd7/7 – Jodrell