Mysql
 sql >> Datenbank >  >> RDS >> Mysql

kann es bei großen Datenmengen schneller ausgeführt werden [MySQL]

Betrachten Sie Ihr EXPLAIN Ausgabe hatte ich Bedenken, dass Ihre Verwendung von Unterabfragen zu einer suboptimalen Verwendung von Indizes geführt hatte. Ich fühlte (ohne Begründung - und da kann ich mich sehr gut irren) dieses Umschreiben mit JOIN kann zu einer optimierteren Abfrage führen.

Dazu müssen wir verstehen, was Ihre Anfrage bezwecken soll. Es hätte geholfen, wenn Ihre Frage es artikuliert hätte, aber nach ein wenig Kopfkratzen entschied ich, dass Ihre Abfrage versuchte, eine Liste aller anderen Schlüsselwörter abzurufen, die in jedem Artikel erscheinen, der ein bestimmtes Schlüsselwort enthält, zusammen mit einer Anzahl aller Artikel, in denen diese Schlüsselwörter vorkommen .

Lassen Sie uns nun die Abfrage schrittweise neu erstellen:

  1. Rufen Sie "jeden Artikel ab, der ein bestimmtes Schlüsselwort enthält " (keine Sorge um Duplikate):

    SELECT ca2.article_id
    FROM
           career_article_keyword AS ca2
    WHERE
          ca2.keyword_id = 9;
    
  2. Rufen Sie "alle anderen Schlüsselwörter ab, die in [oben] vorkommen "

    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. Rufen Sie "[das Obige] zusammen mit einer Anzahl aller Artikel ab, in denen diese Schlüsselwörter vorkommen "

    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. Schließlich wollen wir der Ausgabe das passende Schlüsselwort selbst aus dem career_keyword hinzufügen Tabelle:

    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;
    

Eine Sache, die sofort klar ist, ist, dass Ihre ursprüngliche Anfrage auf career_keywords verwiesen hat zweimal, während diese umgeschriebene Abfrage diese Tabelle nur einmal referenziert; Dies allein könnte den Leistungsunterschied erklären - versuchen Sie, den zweiten Verweis darauf zu entfernen (d. h. dort, wo er in Ihrer ersten Unterabfrage erscheint), da er dort völlig überflüssig ist.

Wenn wir auf diese Abfrage zurückblicken, können wir sehen, dass Joins für die folgenden Spalten durchgeführt werden:

  • career_keywords.keyword_id in ck JOIN ca0

    Diese Tabelle definiert PRIMARY KEY (`keyword_id`) , also gibt es einen guten Index, der für diesen Join verwendet werden kann.

  • career_article_keyword.article_id in ca1 JOIN ca2

    Diese Tabelle definiert UNIQUE KEY `article_id` (`article_id`,`keyword_id`) und seit article_id die Spalte ganz links in diesem Index ist, gibt es einen guten Index, der für diesen Join verwendet werden kann.

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

    Es gibt keinen Index, der für diesen Join verwendet werden kann:Der einzige in dieser Tabelle definierte Index hat eine weitere Spalte, article_id links von keyword_id - MySQL kann also keyword_id nicht finden Einträge im Index, ohne vorher die article_id zu kennen . Ich schlage vor, Sie erstellen einen neuen Index mit keyword_id als Spalte ganz links.

    (Die Notwendigkeit dieses Indexes hätte auch direkt durch Betrachten Ihrer ursprünglichen Abfrage festgestellt werden können, wo Ihre beiden äußersten Abfragen Joins für diese Spalte durchführen.)