2014-01-13 100 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