1

我有一個SQL Server 2008 CTE,它負責返回頂級評論的位置。提高SQL Server 2008性能的幫助CTE

CTE包裝在一個UDF(表值),並加入LocationId字段,所以我可以得到每個位置的最佳評論。

基數

位置具有0一對多 PostLocations
PostLocation具有後
郵政有評論

這裏的UDF:

CREATE FUNCTION [dbo].[Review_HighestRated_Aggregated_ByLocation] 
( 

) 
RETURNS TABLE 
AS 
RETURN 
(
    WITH [RankedLocations] AS 
    (
     SELECT  PL.LocationId, 
        R.Rating, 
        P.PostID, 
        P.UniqueUri, 
        P.Content, 
        ROW_NUMBER() OVER (PARTITION BY PL.LocationId ORDER BY R.Rating DESC, P.LocationTypeId, P.CreatedOn DESC) As ScoreRank 

     From  dbo.PostLocations As PL 
     INNER JOIN dbo.Posts As P 
     ON   P.PostId = PL.PostId 
     INNER JOIN dbo.Reviews As R 
     ON   R.PostId = P.PostId 

     WHERE  R.ReviewTypeId <> 5 
     AND   P.Content IS NOT NULL 
    ) 

    SELECT LocationId, Rating, PostID, UniqueUri, Content 
    FROM RankedLocations 
    WHERE ScoreRank = 1 
) 

下面是如何使用它正在一個例子:

select l.LocationId, l.Name, l.UniqueUri, r.UniqueUri, r.Content 
from @Locations l -- temp table containing around 18 location ids 
inner join dbo.Review_HighestRated_Aggregated_ByLocation() r 
on l.LocationId = r.LocationId 

上述查詢正在15秒來執行,這是不可接受的。沒有加入UDF就需要0秒。

關於如何改善它的任何想法?

如果我看執行計劃,那就是SORT,它佔用了執行成本的98%。該操作的IO /子樹成本約爲300。

我當時希望執行計劃能給我一個提示,指出我可以通過創建來提高成本,但是我什麼也得不到。

任何想法?

+0

是否有`R.ReviewTypeId`上的索引?你是否有用於外鍵關係的列(三個表中的`PostId`)?另外:另一種選擇是嘗試直接在查詢中使用CTE,而不是將其隱藏在UDF中(可能會出現很慢的緩慢......) - 這是否有所不同? – 2011-02-18 05:45:04

+0

@marc_s。是的,ReviewTypeId上有一個索引。是的,PostId是Post上的羣集PK,PostLocations上的羣集PK的一部分,以及評論中的羣集PK。我也試過直接使用CTE,沒有改變。我試圖創建一個視圖,這很好 - 但是你不能索引一個具有聚合操作的視圖或子查詢。目前,我傾向於一個「緩存表」,每隔一小時左右更新一次sql預定作業。想法? – RPM1984 2011-02-21 04:49:55

回答

2

所以我發現性能問題,它不是CTE,它是我如何使用它。

我有幾個查找表,特別是位置類型(街道= 7,城市= 5等)。

因此,爲了保持我的SQL流利的和一貫的(並避免硬編碼的幻數),我創建了一個包裝標量函數返回一個基於字符串的evuivalent值,例如:

DECLARE @Street_LocationType = [dbo].[ToLocationTypeId]('Street') 

功能是非常簡單,只是一系列的CASE陳述。

但是,我用我的CTE這樣的:

SELECT  a.LocationId, b.Content, b.UniqueUri 
FROM  [dbo].[Locations] a 
INNER JOIN dbo.Review_HighestRated_Aggregated_ByLocation() b -- UDF with CTE 
ON   a.LocationId = b.LocationId   
WHERE  a.LocationTypeId = @Street_LocationType 

,所以我沒即使使用它的CTE本身,我用它作爲在位置表中的過濾器。

如果我改變上面的硬編碼值(例如7),程序執行時間從13秒降到2秒。

我不明白,但它解決了這個問題。我注意到程序執行不當時,查詢計劃中的「SORT」操作估計有多少行= 32,000 - 這基本上是系統中的每個帖子。

我的更改後,估計的行數是1(因爲它應該是)。

確實是奇怪的活動。

0

要CTE和UDF轉換成一個觀點:

DROP FUNCTION [dbo].[Review_HighestRated_Aggregated_ByLocation] 
GO 

CREATE VIEW Review_HighestRated_Aggregated_ByLocation 
AS 
SELECT LocationId, Rating, PostID, UniqueUri, Content 
FROM 
(
    SELECT  PL.LocationId, 
       R.Rating, 
       P.PostID, 
       P.UniqueUri, 
       P.Content, 
       ROW_NUMBER() OVER (PARTITION BY PL.LocationId ORDER BY R.Rating DESC, P.LocationTypeId, P.CreatedOn DESC) As ScoreRank 
    From  dbo.PostLocations As PL 
    INNER JOIN dbo.Posts As P 
    ON   P.PostId = PL.PostId 
    INNER JOIN dbo.Reviews As R 
    ON   R.PostId = P.PostId 
    WHERE  R.ReviewTypeId <> 5 
    AND   P.Content IS NOT NULL 
) RankedLocations 
WHERE ScoreRank = 1 

GO 

OP的示例查詢修改爲使用新的觀點:

select l.LocationId, l.Name, l.UniqueUri, r.UniqueUri, r.Content 
from @Locations l -- temp table containing around 18 location ids 
inner join Review_HighestRated_Aggregated_ByLocation r 
on l.LocationId = r.LocationId 
+0

如果您需要重用UDF中的代碼,將UDF轉換爲View將會有所幫助。 – 2011-02-18 01:04:45

0

如果您的表值函數不需要參數考慮使用一個VIEW而不是一個UDF。可能它解決了性能問題。