MySQL: indice quando si uniscono alle tabelle non utilizzati (Performance ottimizzando questione)
-
16-10-2019 - |
Domanda
Ho bisogno di ottimizzare la seguente query:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM blogposts
JOIN articles ON articles.blogpost_id = blogposts.id
WHERE blogposts.deleted = 0
AND blogposts.title LIKE '%{de}%'
AND blogposts.visible = 1
AND blogposts.date_published <= NOW()
ORDER BY blogposts.date_created DESC
LIMIT 0 , 50
SPIEGARE SELEZIONA mi dà il seguente risultato:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles ALL blogpost_id NULL NULL NULL 6915 Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
Perché in primo luogo prendere gli articoli e poi i blogposts? È perché blogposts hanno più voci? E come posso migliorare la query in modo che l'articlepost può utilizzare un indice?
Aggiornamento: Un indice è impostato su blogposts.date_created. Rimozione della condizione di blogposts.title LIKE e il date_published <= NOW () non fa nulla.
Quando rimuovo il " articles.id AS articleId " può usare l'indice blogpost_id su articoli ... Suona strano per me, qualcuno sa perché? (Perché in realtà ho bisogno ..)
Il nuova spiegare aspetto:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles index blogpost_id blogpost_id 4 NULL 6915 Using index; Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
Soluzione
Ho preso uno sguardo più da vicino la query e si potrebbe essere in grado di ridisegnare esso. Ecco cosa voglio dire:
La parte LIMIT 0,50 della query sembra fatta impegnato nella query scorso.
È possibile migliorare il layout della query nel seguente modo:
Passaggio 1) Creare una query in linea per raccogliere solo le chiavi. In questo caso, l'ID per blogposts.
Punto 2) impone alcun WHERE, clausole ORDER BY e GROUP BY sulla query in linea portando chiavi.
Passo 3) Impost la clausola LIMIT come ultimo passo di rendere la query in linea.
Passo 4) Unire la query in linea con la tabella di blogpost in caso avete bisogno di ulteriori colonne da blogpost come blostpost temptable
Passo 5) Iscriviti a questo nuovo temptable blogpost con la tabella articoli.
I passaggi 1-3 ha lo scopo di creare un temptable con esattamente 50 righe e includere l'ID blogpost. Quindi, eseguire tutti i join morti scorso.
Con questi passaggi applicati alla query originale, si dovrebbe avere in questo modo:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT B.*
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
AND title LIKE '%{de}%'
ORDER BY date_created DESC
LIMIT 0,50
) A
INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
Dal momento che hai modificato la questione e ha dichiarato che potrete eliminare COME, ora la query dovrebbe guardare più simile a questo:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT B.*
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
ORDER BY date_created DESC
LIMIT 0,50
) A
INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
Nella frase [cose omessi], se non hai bisogno di qualsiasi cosa, da blogposts diversi i tasti, quindi la query dovrebbe essere simile a questo:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
ORDER BY date_created DESC
LIMIT 0,50
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
CAVEAT
Assicurati di costruire un indice che coinvolge le colonne eliminate, visibile, e DATE_CREATED come segue:
ALTER TABLE blogposts ADD INDEX deleted_visible_date_created (deleted,visible,date_created);
fare un tentativo !!!
Altri suggerimenti
Il tuo dove condizione blogposts.title LIKE '%{de}%'
causerà una scansione completa della tabella sulla blogposts tavolo. E 'probabile figure MySQL scansione 6915 articoli è più efficiente.
su come migliorarlo, si potrebbe aggiungere un indice su blogposts utilizzando il date_created
o date_published
e aggiungere una gamma al quale condizione (qualcosa di diverso <= NOW ())
E blogposts.title LIKE '% {de}%' - Inutile per l'ottimizzazione (leader wild card)
dove blogposts.deleted = 0 E blogposts.visible = 1 - Yuck:. Se essi non dovrebbero essere mostrati, farli fuori dalla tabella
E blogposts.date_published <= NOW () ORDER BY DESC blogposts.date_created LIMIT 0, 50 - che conduce al bisogno INDEX (date_published) (Tuttavia, il LIKE e bandiere possono impedire questo indice venga utilizzato.)
Si prega di fornire SHOW CREATE TABLE ...; SHOW TABLE STATUS ...;
Grazie mille:)
ho dato una prova e ha scoperto che in realtà il tuo ultimo commento circa l'indice era la cosa di cui avevo bisogno. A volte è solo qualche piccolo miglioramento che è necessario ...;) Confronto:
Old query:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM blogposts
JOIN articles ON articles.blogpost_id = blogposts.id
WHERE blogposts.deleted = 0
AND blogposts.title LIKE '%{de}%'
AND blogposts.visible = 1
AND blogposts.date_published <= NOW()
ORDER BY blogposts.date_created DESC
LIMIT 0 , 50
Nuova query:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT B.*
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
AND title LIKE '%{de}%'
ORDER BY date_created DESC
LIMIT 0,50
) A
INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id
Ora, senza l'indice menzionato:
Old Spiegate Risultato:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles ALL blogpost_id NULL NULL NULL 6915 Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
Nuova Spiegate Risultato:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 50
1 PRIMARY articles ref blogposts_id blogposts_id 4 blogposts.id 1
2 DERIVED <derived3> ALL NULL NULL NULL NULL 50
2 DERIVED B eq_ref PRIMARY PRIMARY 4 A.id 1
3 DERIVED blogposts ALL deleted,visible,date_published deleted 1 28198 Using filesort
Risultati Spiega con indice sulla vecchia query:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE blogposts ref PRIMARY,deleted,visible,date_published,deleted_vis... deleted_visible_date_created 2 const,const 27771 Using where
1 SIMPLE articles ref blogposts_id blogposts_id 4 db.blogposts.id 1
Risultati Spiega con indice su nuova query:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 50
1 PRIMARY articles ref blogposts_id blogposts_id 4 blogposts.id 1
2 DERIVED <derived3> ALL NULL NULL NULL NULL 50
2 DERIVED B eq_ref PRIMARY PRIMARY 4 A.id 1
3 DERIVED blogposts ref deleted,visible,date_published,deleted_visible_dat... deleted_visible_date_created 2 27771 Using where
Velocità sulla vecchia query senza / con indice: 0,1835 / 0,0037
Velocità sulla nuova query senza / con indice: 0,1883 / 0,0035
Quindi, a causa della differency solo marginale tra la vecchia / nuova query preferisco utilizzare ancora il vecchio query, ma con l'indice. Ma io tenere questo in mente, come se un giorno il vecchio query è troppo lento:)
Quale potrebbe essere interessante per me è sapere, come è venuta l'idea per impostare l'indice di come questo? Penso che come ho pubblicato questa domanda, ho provato anche con deleted_visible ma invece di DATE_CREATED ho usato date_published (come è nella clausola where) ...
Grazie:)
UPDATE da RolandoMySQLDBA 2011-05-19 13:03
Che ha dato via per me era la WHERE e ORDER BY.
Nella clausola WHERE, cancellato (0) e visibile (1) sono valori statici. era dell'ordine BY, il DATE_CREATED come un bersaglio in movimento tra tutte le righe con soppresso = 0 e visibile = 1. Così, ho messo le variabili statiche di fronte dell'indice, poi il bersaglio in movimento ultima nell'indice. Solitamente, che fa parte del principio fondamentale della refactoring istruzioni SQL. Avete bisogno di indici in grado di supportare il vostro WHERE, GROUP BY e ORDER clausole.