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
È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a dba.stackexchange
scroll top