如何优化此SQL查询? (电影数据库)

时间:2011-02-09 18:59:20

标签: mysql query-optimization

我正在使用MySQL,出于某种原因需要花费大量时间来执行这样的查询:

SELECT 
  DISTINCT (Movies.id) AS id, 
  Movies.UnMoID AS UnMoID, 
  Movies.runtime AS runtime
FROM 
  Movies
INNER JOIN Acted ON Acted.UnMoID = Movies.UnMoID
INNER JOIN Actors ON Acted.UnMoActorID = Actors.UnMoActorID
INNER JOIN Directed ON Directed.UnMoID = Movies.UnMoID
INNER JOIN Directors ON Directed.UnMoDirectorID = Directors.UnMoDirectorID
WHERE 
  Actors.name LIKE '%spiderman%'
  OR Directors.name LIKE '%spiderman%'
  OR Movies.originalTitle LIKE '%spiderman%'
  OR Movies.englishTitle LIKE '%spiderman%'
  OR Movies.alsoKnownAs LIKE '%spiderman%'
  OR Movies.taglines LIKE '%spiderman%'
  OR Movies.plot LIKE '%spiderman%'
  AND Movies.validated =1
  AND Movies.ageCertificate <=20
GROUP BY Movies.id
ORDER BY added DESC

这会让我:“在6.5320秒内执行查询并得到2个结果。”

解释这个特定的查询给出:

id  select_type  table     type   possible_keys          key            key_len  ref                            rows  Extra
1   SIMPLE       Movies    ALL    UnMoID                 NULL           NULL     NULL                           925   Using temporary; Using filesort
1   SIMPLE       Directed  ref    UnMoID,UnMoDirectorID  UnMoID         62       Movies.Movies.UnMoID             1    
1   SIMPLE       Directors eq_ref UnMoDirectorID         UnMoDirectorID 62       Movies.Directed.UnMoDirectorID   1    
1   SIMPLE       Acted     ref    UnMoID,UnMoActorID     UnMoID         62       Movies.Movies.UnMoID            34   
1   SIMPLE       Actors    eq_ref UnMoActorID            UnMoActorID    62       Movies.Acted.UnMoActorID         1   Using where

概要信息:

......
Creating tmp table    0.000032
Sorting for group     0.000007
executing             0.000005
Copying to tmp table  6.324177
Sorting result        0.000027
Sending data          0.000019
......

在最糟糕的情况下,执行查询最多需要20秒,并且每次大部分时间都转到Copying to tmp table。那么,我该怎么做才能优化我的查询并获得合理的查询时间。

我有以下索引:

Movies.id                 PRIMARY
Movies.UnMoID             UNIQUE
Movies.runtime            INDEX
Acted.UnMoID              INDEX
Acted.UnMoActorID         INDEX
Actors.UnMoActorID        UNIQUE
Actors.name               UINDEX
Directed.UnMoID           INDEX
Directed.UnMoDirectorID   INDEX
Directors.UnMoDirectorID  UNIQUE
Directors.name            INDEX
Movies.originalTitle      INDEX
Movies.englishTitle       INDEX
Movies.alsoKnownAs        INDEX
Movies.taglines           INDEX
Movies.plot               INDEX

3 个答案:

答案 0 :(得分:2)

索引无法帮助LIKE搜索前导通配符。您可能需要考虑实施full-text search

答案 1 :(得分:1)

类似搜索的MYSQL非常慢,全文搜索功能仅在MyISAM中可用。您可以尝试使用具有优化索引的读取从属进行优化,但不会获得太多收益。

我会将您的查询移至使用SPHINXSOLR(data importer for MYSQL)等搜索引擎。

答案 2 :(得分:0)

我认为缓慢的原因是因为你的病情如此广泛。相反,我会尝试制作简单的查询,然后将它们与UNION结合起来,这也会删除重复项。

所以,这样的事情可能是有益的(我无法真正测试那个声明,因为我没有你的数据库),因为我认为每个个别查询都会非常快,并且合并的记录不会很多:

(SELECT Movies.id, Movies.UnMoID, Movies.runtime, added
FROM Movies INNER JOIN Actors ON Acted.UnMoActorID = Actors.UnMoActorID
WHERE Actors.name LIKE '%spiderman%'
  AND Movies.validated =1
  AND Movies.ageCertificate <=20)
UNION
(SELECT Movies.id, Movies.UnMoID, Movies.runtime, added
FROM Movies INNER JOIN Directed ON Directed.UnMoID = Movies.UnMoID
INNER JOIN Directors ON Directed.UnMoDirectorID = Directors.UnMoDirectorID
WHERE Directors.name LIKE '%spiderman%'
  AND Movies.validated =1
  AND Movies.ageCertificate <=20)
UNION
(SELECT Movies.id, Movies.UnMoID, Movies.runtime, added
FROM Movies 
WHERE Movies.originalTitle LIKE '%spiderman%'
  AND Movies.validated =1
  AND Movies.ageCertificate <=20)
UNION
(SELECT Movies.id, Movies.UnMoID, Movies.runtime, added
FROM Movies 
WHERE Movies.englishTitle LIKE '%spiderman%'
  AND Movies.validated =1
  AND Movies.ageCertificate <=20)
UNION
(SELECT Movies.id, Movies.UnMoID, Movies.runtime, added
FROM Movies 
WHERE Movies.alsoKnownAs LIKE '%spiderman%'
  AND Movies.validated =1
  AND Movies.ageCertificate <=20)
UNION
(SELECT Movies.id, Movies.UnMoID, Movies.runtime, added
FROM Movies 
WHERE Movies.taglines LIKE '%spiderman%'
  AND Movies.validated =1
  AND Movies.ageCertificate <=20)
UNION
(SELECT Movies.id, Movies.UnMoID, Movies.runtime, added
FROM Movies 
WHERE Movies.plot LIKE '%spiderman%'
  AND Movies.validated =1
  AND Movies.ageCertificate <=20)
ORDER BY added DESC

您需要在查询结果中包含要对其进行排序或过滤的字段。

如果您有一个支持子选择的引擎,您可以将验证和年龄证明的过滤条件从单个查询中移出到公共包装查询中,其中的好处主要是删除重复,因此,维护:

 SELECT id, UnMoID, runtime FROM
 (SELECT ... ) Q   -- the above query including all necessary fields
 WHERE Movies.validated =1
 AND Movies.ageCertificate <=20
 ORDER BY added DESC