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

può essere eseguito più velocemente con una grande quantità di dati [MySQL]

Guardando il tuo EXPLAIN output, ero preoccupato che l'uso delle sottoquery avesse comportato un uso non ottimale degli indici. mi sono sentito (senza alcuna giustificazione - e su questo potrei benissimo sbagliarmi) quella riscrittura usando JOIN potrebbe portare a una query più ottimizzata.

Per fare ciò, dobbiamo capire a cosa serve la tua richiesta. Sarebbe stato d'aiuto se la tua domanda l'avesse articolata, ma dopo un piccolo grattacapo ho deciso che la tua query stava cercando di recuperare un elenco di tutte le altre parole chiave che appaiono in qualsiasi articolo che contiene una determinata parola chiave, insieme a un conteggio di tutti gli articoli in cui compaiono tali parole chiave .

Ora ricostruiamo la query in più fasi:

  1. Recupera "qualsiasi articolo che contiene una determinata parola chiave " (senza preoccuparsi dei duplicati):

    SELECT ca2.article_id
    FROM
           career_article_keyword AS ca2
    WHERE
          ca2.keyword_id = 9;
    
  2. Recupera "tutte le altre parole chiave che appaiono in [sopra] "

    SELECT ca1.keyword_id
    FROM
           career_article_keyword AS ca1
      JOIN career_article_keyword AS ca2 ON (ca2.article_id = ca1.article_id)
    WHERE
          ca1.keyword_id <> 9
      AND ca2.keyword_id =  9
    GROUP BY ca1.keyword_id;
    
  3. Recupera "[quanto sopra], insieme a un conteggio di tutti gli articoli in cui compaiono quelle parole chiave "

    SELECT ca1.keyword_id, COUNT(DISTINCT ca0.article_id) AS cnt
    FROM
           career_article_keyword AS ca0
      JOIN career_article_keyword AS ca1 USING (keyword_id)
      JOIN career_article_keyword AS ca2 ON (ca2.article_id = ca1.article_id)
    WHERE
          ca1.keyword_id <> 9
      AND ca2.keyword_id =  9
    GROUP BY ca1.keyword_id
    ORDER BY cnt DESC;
    
  4. Infine, vogliamo aggiungere all'output la stessa parola chiave corrispondente da career_keyword tabella:

    SELECT ck.keyword_id, ck.keyword, COUNT(DISTINCT ca0.article_id) AS cnt
    FROM
           career_keywords        AS ck 
      JOIN career_article_keyword AS ca0 USING (keyword_id)
      JOIN career_article_keyword AS ca1 USING (keyword_id)
      JOIN career_article_keyword AS ca2 ON (ca2.article_id = ca1.article_id)
    WHERE
          ca1.keyword_id <> 9
      AND ca2.keyword_id =  9
    GROUP BY ck.keyword_id -- equal to ca1.keyword_id due to join conditions
    ORDER BY cnt DESC;
    

Una cosa che è immediatamente chiara è che la tua query originale faceva riferimento a career_keywords due volte, mentre questa query riscritta fa riferimento a quella tabella solo una volta; questo da solo potrebbe spiegare la differenza di prestazioni:prova a rimuovere il secondo riferimento ad esso (ovvero dove appare nella tua prima sottoquery), poiché lì è del tutto ridondante.

Guardando indietro a questa query, possiamo vedere che i join vengono eseguiti sulle seguenti colonne:

  • career_keywords.keyword_id in ck JOIN ca0

    Questa tabella definisce PRIMARY KEY (`keyword_id`) , quindi esiste un buon indice che può essere utilizzato per questo join.

  • career_article_keyword.article_id in ca1 JOIN ca2

    Questa tabella definisce UNIQUE KEY `article_id` (`article_id`,`keyword_id`) e, poiché article_id è la colonna più a sinistra di questo indice, c'è un buon indice che può essere utilizzato per questo join.

  • career_article_keyword.keyword_id in ck JOIN ca0 e ca0 JOIN ca1

    Non esiste alcun indice che può essere utilizzato per questo join:l'unico indice definito in questa tabella ha un'altra colonna, article_id a sinistra di keyword_id - quindi MySQL non riesce a trovare keyword_id voci nell'indice senza prima conoscere l'article_id . Ti suggerisco di creare un nuovo indice che abbia keyword_id come colonna più a sinistra.

    (La necessità di questo indice potrebbe ugualmente essere stata accertata guardando la tua query originale, dove le tue due query più esterne eseguono join su quella colonna.)