2011-05-19 65 views
0

我的查詢很慢。我在3個表格之間搜索。 Se_movies = 80000條記錄,se_movie_contenttags = 1.6 mil記錄,se_movie_description標籤-200000條記錄我的SQL查詢非常慢(60秒),任何人有想法改進?

兩個簡化查詢。

OR - 慢

SELECT SQL_NO_CACHE count(movie_id) 
FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id 
LEFT JOIN 
( 
    SELECT did , cid , ifnull(cid,did) as uid FROM (SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog')) AS dtag 
    LEFT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog')) AS ctag 
    ON dtag.did=ctag.cid 
UNION 
    SELECT did , cid , ifnull(cid,did) as uid FROM (SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog')) AS dtag 
    RIGHT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog')) AS ctag 
    ON dtag.did=ctag.cid 
) 
AS tagobjects ON se_movies.movie_id=tagobjects.uid 
WHERE (se_movies.movie_title LIKE '%dog%') **OR** ( (cid IS NOT NULL or did IS NOT NULL) and uid IS NOT NULL) 

AND - 快速

SELECT SQL_NO_CACHE count(movie_id) 
FROM se_movies LEFT JOIN se_users ON se_movies.movie_user_id=se_users.user_id 
LEFT JOIN 
( 
    SELECT did , cid , ifnull(cid,did) as uid FROM (SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog')) AS dtag 
    LEFT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog')) AS ctag 
    ON dtag.did=ctag.cid 
UNION 
    SELECT did , cid , ifnull(cid,did) as uid FROM (SELECT tag_object_id AS did FROM se_movie_descriptiontags WHERE tag_name IN ('dog')) AS dtag 
    RIGHT JOIN (SELECT tag_object_id AS cid FROM se_movie_contenttags WHERE tag_name IN ('dog')) AS ctag 
    ON dtag.did=ctag.cid 
) 
AS tagobjects ON se_movies.movie_id=tagobjects.uid 
WHERE (se_movies.movie_title LIKE '%dog%') **AND** ( (cid IS NOT NULL or did IS NOT NULL) and uid IS NOT NULL) 

每一個單獨

(se_movies.movie_title LIKE '%dog%') - around 300 
(cid IS NOT NULL or did IS NOT NULL) and uid IS NOT NULL - return 595 

,但它是快,如果任何人他們返回大約50或更少。

基本上如果任何關鍵字具有在上述各標籤和電影表標題500 ...它需要60秒

否則2.3秒。

有沒有更好的方法?

我知道u能這兩個... 之間和其他的東西做UNION ...

搜索 - 冠軍OR(或CONTENTTAG desctag)

問題是查詢的太多變化...

是否問題在做或者如果數據在兩個不同的表中?無論如何加快它們?

謝謝。

系統 - mysql apache2 php5 ubuntu - 亞馬遜aws。

解釋 enter link description here

解決它BY

SELECT SQL_NO_CACHE計數(movie_id) FROM se_movies LEFT JOIN se_users ON se_movies.movi​​e_user_id = se_users.user_id INNER JOIN (SELECT tag_object_id AS movieid FROM se_movie_contenttags WHERE tag_name IN('dog') UNION SELECT tag_object_id AS movieid FROM se_movie_descriptiontags WHERE tag_name IN('dog') UNION SELECT s1.movi​​e_id AS movieid FROM se_movies爲S1 WHERE s1.movi​​e_title LIKE '%狗%' UNION SELECT s2.movi​​e_id AS movieid FROM se_movies爲S2 WHERE s2.movi​​e_desc LIKE '%狗%' ) AS tagobjects ON se_movies.movi​​e_id = tagobjects.movi​​eid

。5秒

+2

請讓我們知道您的表上有哪些索引 - 並將EXPLAIN SELECT ...的輸出附加到您的問題。 – 2011-05-19 22:27:40

+0

是否故意在慢查詢中的OR子句之後的術語沒有與其他子句括起來?您目前實際上有(A和B和C和D)或E,即 - 如果OR子句的RHS爲真,則AND並不重要。 – 2011-05-19 22:36:46

回答

0

如果se_movie_descriptiontagsse_movie_contenttags包含對(movie_id, tag)並且要包括具有一定標籤的所有電影,我將取代tagobjects在線視圖:

SELECT `tag_object_id` AS `uid` FROM `se_movie_descriptiontags` 
WHERE `tag_name` IN ('dog') 
UNION 
SELECT `tag_object_id` FROM `se_movie_contenttags` 
WHERE `tag_name` IN ('dog') 

這個查詢將返回電影IDS在se_movie_descriptiontagsse_movie_contenttags表中的任何一個或兩個都有標籤'dog'。然後你可以在主查詢中刪除OR ((cid IS NOT NULL OR did IS NOT NULL) AND uid IS NOT NULL)

最終的完整的查詢將是:

SELECT SQL_NO_CACHE count(movie_id) 
FROM 
    se_movies LEFT JOIN 
    se_users ON se_movies.movie_user_id=se_users.user_id INNER JOIN 
    ( 
     SELECT `tag_object_id` AS `uid` FROM `se_movie_descriptiontags` 
     WHERE `tag_name` IN ('dog') 
     UNION 
     SELECT `tag_object_id` FROM `se_movie_contenttags` 
     WHERE `tag_name` IN ('dog') 
    ) AS tagobjects ON se_movies.movie_id=tagobjects.uid 
WHERE (se_movies.movie_title LIKE '%dog%') 

另外請注意,單獨(se_movies.movie_title LIKE '%dog%')是性能殺手,因爲它無法通過在movie_title列使用索引進行優化,肯定會引起表掃描。這主要是由於條件以通配符開始的事實。對於這種情況,我建議查看MySQL的全文搜索功能。

+0

想法允許在JOIN中不在類中的邏輯。我基本上用desc標誌,內容標誌爲該關鍵字創建一個臨時表,所以我可以在將來做到這一點。 1.內容或desc或標題。 2.(內容和desc)或標題3.內容和標題..等 – alex 2011-05-19 23:08:42

+0

在這種情況下,我認爲NoSQL更適合您正在嘗試完成。 – Xint0 2011-05-19 23:15:27

+0

我正在嘗試標題或desc標籤或內容標籤。我知道那個keyowrd中的inner join optiion已經存在於標籤中,然後在這種情況下你還需要使用tagobjects.uid = null。我只想了解在搜索主表和連接表值的OR問題...它似乎是重複表掃描多次... – alex 2011-05-19 23:22:11