Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

pode ser executado mais rápido com grande quantidade de dados [MySQL]


Olhando para o seu EXPLAIN saída, eu estava preocupado que seu uso de subconsultas resultou em um uso abaixo do ideal de índices. Eu senti (sem qualquer justificativa - e nisso eu posso muito bem estar errado) que reescrever usando JOIN pode levar a uma consulta mais otimizada.

Para fazer isso, precisamos entender o que sua consulta pretende fazer. Teria ajudado se sua pergunta tivesse articulado, mas depois de um pouco de coçar a cabeça, decidi que sua consulta estava tentando buscar uma lista de todas as outras palavras-chave que aparecem em qualquer artigo que contenha uma determinada palavra-chave, juntamente com uma contagem de todos os artigos em que essas palavras-chave aparecem .

Agora vamos reconstruir a consulta em etapas:

  1. Buscar "qualquer artigo que contenha uma determinada palavra-chave " (sem se preocupar com duplicatas):
    SELECT ca2.article_id
    FROM
           career_article_keyword AS ca2
    WHERE
          ca2.keyword_id = 9;
    

  2. Buscar "todas as outras palavras-chave que aparecem em [acima] "
    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. Buscar "[o acima], juntamente com uma contagem de todos os artigos em que essas palavras-chave aparecem "
    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. Finalmente, queremos adicionar à saída a palavra-chave correspondente da career_keyword tabela:
    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;
    

Uma coisa que fica imediatamente clara é que sua consulta original fazia referência a career_keywords duas vezes, enquanto essa consulta reescrita faz referência a essa tabela apenas uma vez; isso por si só pode explicar a diferença de desempenho - tente remover a segunda referência a ela (ou seja, onde ela aparece em sua primeira subconsulta), pois é totalmente redundante lá.

Olhando para esta consulta, podemos ver que as junções estão sendo executadas nas seguintes colunas:

  • career_keywords.keyword_id em ck JOIN ca0

    Esta tabela define PRIMARY KEY (`keyword_id`) , portanto, há um bom índice que pode ser usado para essa junção.

  • career_article_keyword.article_id em ca1 JOIN ca2

    Esta tabela define UNIQUE KEY `article_id` (`article_id`,`keyword_id`) e, como article_id é a coluna mais à esquerda neste índice, existe um bom índice que pode ser usado para esta junção.

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

    Não há índice que possa ser usado para esta junção:o único índice definido nesta tabela tem outra coluna, article_id à esquerda de keyword_id - então o MySQL não pode encontrar keyword_id entradas no índice sem primeiro conhecer o article_id . Sugiro que você crie um novo índice que tenha keyword_id como sua coluna mais à esquerda.

    (A necessidade desse índice também pode ter sido determinada diretamente ao examinar sua consulta original, onde suas duas consultas externas realizam junções nessa coluna.)