sql >> Databasteknik >  >> RDS >> Mysql

kan det köras snabbare med stora mängder data [MySQL]

Tittar på din EXPLAIN output, var jag orolig för att din användning av underfrågor hade resulterat i en suboptimal användning av index. Jag kände (utan någon motivering - och om detta kan jag mycket väl ha fel) denna omskrivning med JOIN kan leda till en mer optimerad fråga.

För att göra det måste vi förstå vad det är din fråga är avsedd att göra. Det skulle ha hjälpt om din fråga hade formulerat det, men efter lite huvudskrapa bestämde jag mig för att din fråga försökte hämta en lista över alla andra sökord som förekommer i en artikel som innehåller ett givet nyckelord, tillsammans med en räkning av alla artiklar där dessa sökord förekommer .

Låt oss nu bygga om frågan i etapper:

  1. Hämta "alla artiklar som innehåller ett visst sökord " (inte oroa dig för dubbletter):

    SELECT ca2.article_id
    FROM
           career_article_keyword AS ca2
    WHERE
          ca2.keyword_id = 9;
    
  2. Hämta "alla andra sökord som visas i [ovan] "

    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. Hämta "[ovanstående], tillsammans med en räkning av alla artiklar där dessa sökord förekommer "

    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. Slutligen vill vi lägga till själva det matchande sökordet från career_keyword till utdata tabell:

    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;
    

En sak som är omedelbart tydlig är att din ursprungliga fråga refererade till career_keywords två gånger, medan denna omskrivna fråga endast refererar till den tabellen en gång; Bara detta kan förklara prestandaskillnaden – försök att ta bort den andra referensen till den (dvs. där den visas i din första underfråga), eftersom den är helt överflödig där.

När vi ser tillbaka på den här frågan kan vi se att kopplingar utförs i följande kolumner:

  • career_keywords.keyword_id i ck JOIN ca0

    Den här tabellen definierar PRIMARY KEY (`keyword_id`) , så det finns ett bra index som kan användas för denna join.

  • career_article_keyword.article_id i ca1 JOIN ca2

    Den här tabellen definierar UNIQUE KEY `article_id` (`article_id`,`keyword_id`) och eftersom article_id är kolumnen längst till vänster i detta index, det finns ett bra index som kan användas för denna koppling.

  • career_article_keyword.keyword_id i ck JOIN ca0 och ca0 JOIN ca1

    Det finns inget index som kan användas för denna koppling:det enda indexet som definieras i den här tabellen har en annan kolumn, article_id till vänster om keyword_id - så MySQL kan inte hitta keyword_id poster i indexet utan att först känna till article_id . Jag föreslår att du skapar ett nytt index som har keyword_id som kolumn längst till vänster.

    (Behovet av detta index kunde likaså ha fastställts direkt genom att titta på din ursprungliga fråga, där dina två yttersta frågor utför kopplingar på den kolumnen.)




  1. Rails 5 form_for med checkbox-array

  2. Returnera det aktuella arbetsstationsnamnet som är anslutet till SQL Server (T-SQL)

  3. Patchpolicy

  4. Återställ en SQLite-databas