2014-01-13 136 views
1

我目前遇到了一個昂貴的SQL查詢的性能問題,我想改進它。提高SQL查詢的性能

這是查詢的樣子:

SELECT TOP 50 MovieID 
FROM (SELECT [MovieID], COUNT(*) AS c 
     FROM [tblMovieTags] 
     WHERE [TagID] IN (SELECT TOP 7 [TagID] 
         FROM [tblMovieTags] 
         WHERE [MovieID]=12345 
         ORDER BY Relevance ASC) 
     GROUP BY [MovieID] 
     HAVING COUNT(*) > 1) a 
INNER JOIN [tblMovies] m ON m.MovieID=a.MovieID 
WHERE (Hidden=0) AND m.Active=1 AND m.Processed=1 
ORDER BY c DESC, m.IMDB DESC 

我試圖找到至少有2個MovieID 12345

數據庫基本方案匹配的標籤的電影看起來像: http://i.imgur.com/r5KpgkJ.png

每部電影都有4到5個標籤。我想要一個基於標籤的電影列表。最少2個標籤必須匹配。

此查詢導致我的服務器問題,因爲在任何給定時間我有數百個併發用戶。

我已經根據執行計劃的建議創建了索引,這使得它更快,但它還不夠。

有什麼我可以做的,使這個更快?

+1

你應該像這樣緩存半不可變的東西。 –

+0

建議1 - 永遠不要使用count(*)總是使用count(some_key) –

+0

也許http://msdn.microsoft.com/en-us/library/dd171921%28SQL.100%29.aspx – Mihai

回答

1

我喜歡用臨時表,因爲它們可以加快查詢速度(如果正確使用),並使其更容易閱讀。嘗試使用下面的查詢,看看它是否加快了速度。有幾個字段(隱藏的,imdb)不在您的模式中,因此我將它們排除在外。

此查詢可能會或可能不會完全符合您的要求。重點是向您展示如何使用臨時表來提高性能並提高可讀性。一些小的調整可能是必要的。

SELECT TOP 7 [TagID],[MovieTagID],[MovieID] 
INTO #MovieTags 
FROM [tblMovieTags] 
WHERE [MovieID]=12345 

SELECT mt.MovieID, COUNT(mt.MovieTagID) 
INTO #Movies 
FROM #MovieTags mt 
INNER JOIN tblMovies m ON m.MovieID=mt.MovieID AND m.Active=1 AND m.Process=1 
GROUP BY [MovieID] 
HAVING COUNT(mt.MovieTagID) > 1 

SELECT TOP 50 * FROM #Movies 
DROP TABLE #MovieTags 
DROP TABLE #Movies 

編輯

參數化查詢

你也想使用參數化查詢,而不是在你的SQL字符串串聯你的價值觀。看看這個short, to the point, blog,這解釋了爲什麼你應該使用參數化查詢。這與臨時表方法結合在一起會顯着提高您的性能。

+0

INNER JOIN #MovieTags TMT ON mt.MovieTagID = tmt.MovieTagID應不MovieTagID – Charles380

+0

其實標籤識別,即加入ISN我只需要從#MovieTags中進行選擇,我編輯了我的查詢 –

+0

我注意到我們的兩個解決方案几乎完全相同,我只是在後臺使用臨時表heh – Charles380

1

我想看看是否有一些不必要的處理髮生在您寫的查詢中。嘗試下面的查詢,讓我們知道它是否更快慢等。如果它甚至獲得相同的數據。

我只是把這個在一起,因此不能保證在完美的語法

SELECT TOP 7 [TagID] 
INTO #MovieTags 
FROM [tblMovieTags] 
WHERE [MovieID]=12345 
ORDER BY TagID 

;cte_movies AS 
(
    SELECT 
     mt.MovieID 
     ,mt.TagID 
    FROM 
     tblMovieTags mt 
       INNER JOIN #MovieTags t ON mt.TagId = t.TagId 
       INNER JOIN tblMovies m ON mt.MovieID = m.MovieID 
    WHERE 
     (Hidden=0) AND m.Active=1 AND m.Processed=1 
), 
cte_movietags AS 
(
    SELECT 
     MovieId 
     ,COUNT(MovieId) AS TagCount 
    FROM 
     cte_movies 
    GROUP BY MovieId 
) 
SELECT 
    MovieId 
FROM 
    cte_movietags 
WHERE 
    TagCount > 1 
ORDER BY 
    MovieId 
GO 

DROP TABLE #MovieTags 
+0

感謝您的嘗試!我嘗試過,但結果稍差。原始查詢的平均執行時間大約爲1200,但這個查詢平均需要1900個:( – Aki

+0

)現在怎麼樣,它僅限於tagID排序的前7個標籤? – Charles380

+0

我第一次運行這個查詢,花了6500ms,每個時間之後,它需要1500毫秒。不過我需要什麼太慢由於大量此查詢請求:( – Aki