2010-06-18 8 views
0

저장 프로 시저를 실행하는 데 많은 시간이 걸립니다. 동일한 결과 집합을 얻을 수 있도록 더 나은 승인을 제안 할 수있는 사람이있을 수 있습니까?저장 프로 시저 최적화

ALTER PROCEDURE [dbo].[spFavoriteRecipesGET] 
@USERID INT, @PAGENUMBER INT, @PAGESIZE INT, @SORTDIRECTION VARCHAR(4), @SORTORDER VARCHAR(4),@FILTERBY INT 
AS 
BEGIN 

    DECLARE 
     @ROW_START INT 
    DECLARE 
     @ROW_END INT 
    SET 
     @ROW_START = (@PageNumber-1)* @PageSize+1 
    SET 
     @ROW_END = @PageNumber*@PageSize 

    DECLARE 
     @RecipeCount INT 

    DECLARE 
     @RESULT_SET_TABLE 
    TABLE 
    (
     Id INT NOT NULL IDENTITY(1,1), 
     FavoriteRecipeId INT, 
     RecipeId INT, 
     DateAdded DATETIME, 
     Title NVARCHAR(255), 
     UrlFriendlyTitle NVARCHAR(250), 
     [Description] NVARCHAR(MAX), 
     AverageRatingId FLOAT, 
     SubmittedById INT, 
     SubmittedBy VARCHAR(250), 
     RecipeStateId INT, 
     RecipeRatingId INT, 
     ReviewCount INT, 
     TweaksCount INT, 
     PhotoCount INT, 
     ImageName NVARCHAR(50)    
    ) 
    INSERT INTO @RESULT_SET_TABLE 
     SELECT 
      FavoriteRecipes.FavoriteRecipeId, 
      Recipes.RecipeId, 
      FavoriteRecipes.DateAdded, 
      Recipes.Title, 
      Recipes.UrlFriendlyTitle, 
      Recipes.[Description], 
      Recipes.AverageRatingId, 
      Recipes.SubmittedById, 
      COALESCE(users.DisplayName,users.UserName,Recipes.SubmittedBy) As SubmittedBy, 
      Recipes.RecipeStateId, 
      RecipeReviews.RecipeRatingId, 
      COUNT(RecipeReviews.Review), 
      COUNT(RecipeTweaks.Tweak), 
      COUNT(Photos.PhotoId),  
      dbo.udfGetRecipePhoto(Recipes.RecipeId) AS ImageName 
     FROM 
      FavoriteRecipes 
     INNER JOIN Recipes ON FavoriteRecipes.RecipeId=Recipes.RecipeId AND Recipes.RecipeStateId <> 3 
     LEFT OUTER JOIN RecipeReviews ON RecipeReviews.RecipeId=Recipes.RecipeId AND [email protected] 
     AND RecipeReviews.RecipeRatingId= (
               SELECT MAX(RecipeReviews.RecipeRatingId) 
               FROM RecipeReviews 
               WHERE [email protected] 
               AND RecipeReviews.RecipeId=FavoriteRecipes.RecipeId 
              ) 

     OR RecipeReviews.RecipeRatingId IS NULL 
     LEFT OUTER JOIN RecipeTweaks ON RecipeTweaks.RecipeId = Recipes.RecipeId AND RecipeTweaks.TweakedById= @UserId 
     LEFT OUTER JOIN Photos ON Photos.RecipeId = Recipes.RecipeId 
            AND Photos.UploadedById = @UserId AND Photos.RecipeId = FavoriteRecipes.RecipeId 
            AND Photos.PhotoTypeId = 1 

     LEFT OUTER JOIN users ON Recipes.SubmittedById = users.UserId  
     WHERE 
      [email protected] 
     GROUP BY 
      FavoriteRecipes.FavoriteRecipeId, 
      Recipes.RecipeId, 
      FavoriteRecipes.DateAdded, 
      Recipes.Title, 
      Recipes.UrlFriendlyTitle, 
      Recipes.[Description], 
      Recipes.AverageRatingId, 
      Recipes.SubmittedById, 
      Recipes.SubmittedBy, 
      Recipes.RecipeStateId, 
      RecipeReviews.RecipeRatingId, 
      users.DisplayName, 
      users.UserName, 
      Recipes.SubmittedBy; 

     WITH SortResults 
     AS 
     (
       SELECT 
       ROW_NUMBER() OVER (
        ORDER BY CASE WHEN @SORTDIRECTION = 't' AND @SORTORDER='a' THEN TITLE END ASC, 
          CASE WHEN @SORTDIRECTION = 't' AND @SORTORDER='d' THEN TITLE END DESC, 
          CASE WHEN @SORTDIRECTION = 'r' AND @SORTORDER='a' THEN AverageRatingId END ASC, 
          CASE WHEN @SORTDIRECTION = 'r' AND @SORTORDER='d' THEN AverageRatingId END DESC, 
          CASE WHEN @SORTDIRECTION = 'mr' AND @SORTORDER='a' THEN RecipeRatingId END ASC, 
          CASE WHEN @SORTDIRECTION = 'mr' AND @SORTORDER='d' THEN RecipeRatingId END DESC, 
          CASE WHEN @SORTDIRECTION = 'd' AND @SORTORDER='a' THEN DateAdded END ASC, 
          CASE WHEN @SORTDIRECTION = 'd' AND @SORTORDER='d' THEN DateAdded END DESC 
       ) RowNumber, 
       FavoriteRecipeId, 
       RecipeId, 
       DateAdded, 
       Title, 
       UrlFriendlyTitle, 
       [Description], 
       AverageRatingId, 
       SubmittedById, 
       SubmittedBy, 
       RecipeStateId, 
       RecipeRatingId, 
       ReviewCount, 
       TweaksCount, 
       PhotoCount, 
       ImageName   

      FROM 
       @RESULT_SET_TABLE 
      WHERE 
        ((@FILTERBY = 1 AND SubmittedById= @USERID) 
       OR (@FILTERBY = 2 AND (SubmittedById <> @USERID OR SubmittedById IS NULL)) 
       OR (@FILTERBY <> 1 AND @FILTERBY <> 2)) 
     )   
     SELECT 
      RowNumber, 
      FavoriteRecipeId, 
      RecipeId, 
      DateAdded, 
      Title, 
      UrlFriendlyTitle, 
      [Description], 
      AverageRatingId, 
      SubmittedById, 
      SubmittedBy, 
      RecipeStateId, 
      RecipeRatingId, 
      ReviewCount, 
      TweaksCount, 
      PhotoCount, 
      ImageName 
     FROM 
      SortResults 

     WHERE 
     RowNumber BETWEEN @ROW_START AND @ROW_END 
     print @ROW_START  
     print @ROW_END 
     SELECT 
      @RecipeCount=dbo.udfGetFavRecipesCount(@UserId) 
     SELECT 
      @RecipeCount AS RecipeCount 
     SELECT COUNT(Id) as FilterCount FROM @RESULT_SET_TABLE    
     WHERE  
        ((@FILTERBY = 1 AND SubmittedById= @USERID) 
       OR (@FILTERBY = 2 AND (SubmittedById <> @USERID OR SubmittedById IS NULL)) 
       OR (@FILTERBY <> 1 AND @FILTERBY <> 2)) 


END 
+3

실행 계획을 연구하여 후드 내부에서 어떤 일이 발생하는지 확인 했습니까? 시작할 첫 번째 장소. – Galwegian

+0

아마도 Microsoft SQL Server를 사용하고 있다고 지정해야합니다. – Teekin

+0

누군가가 귀하의 질문에 대한 답을 줄 때 올바른 답을 선택하는 것이 좋습니다 (정답 옆에있는 확인란을 클릭하십시오). 그것은 같은 질문에 대한 답을 빨리 찾고 싶어하는 사람들을 도우며 응답자가 그들이 당신에게 도움이되었다는 것을 알리도록합니다. –

답변

1

시간이 어디로 가고 있는지 확인하려면 실행 계획을 확인해야합니다. 인덱스, UDF로 인한 테이블 스캔 등 여러 가지가있을 수 있습니다. 계획을 세우려고 할 때 질의를 작은 부분으로 나눠서 차이를 만들 수 있는지 확인하십시오.

로컬 테이블없이 할 수 있는지 확인하려면 ROW_NUMBER에 대해 알아보십시오.

1

커플

색인 노트 - 종종 사람들이 임시 테이블 또는 그들이 당신이 그 개체에 대한 인덱스를 만들 수 있습니다 실현하기 위해 실패 테이블 변수이 대규모 성능에 영향을 미칠 수를 사용하는 절차를 만들 때.

UDF - 때로는 쿼리 프로세서가 UDF 논리를 효과적으로 인라인하고 때로는 쿼리 계획을 자세히 살펴보고 이것이 어떻게 처리되는지 확인하십시오. 상관 하위 쿼리와 같이 무언가로 수동으로이 논리를 인라인하면 성능이 크게 향상 될 수 있습니다.

0

OR 주변에 괄호를 추가해야합니다.

1

다른 사람들이 말했듯이, 알고있는 유일한 방법은 설명 플랜을 보는 것입니다. 코드를 통해 반짝이기는하지만,이 부분은 종류의 비린내가 보인다 : 일반적으로

AND RecipeReviews.RecipeRatingId= (
              SELECT MAX(RecipeReviews.RecipeRatingId) 
              FROM RecipeReviews 
              WHERE [email protected] 
              AND RecipeReviews.RecipeId=FavoriteRecipes.RecipeId 
             ) 

아닌 사소한 물건을 조인 조건에서 나쁜 생각입니다. 나는 그것을 하위 선택으로 분해 할 것이고, 외부 결합이기 때문에 아마도 이것을 어떻게 든 RecipeReviews와 결합해야 할 것입니다.

하지만 이것 모두는 추측입니다! 설명! 법안!

1

잘 UDF의 가능한 성능 저하뿐만 아니라, 코드 줄 일반적으로 조인의 일환으로 하위 쿼리를 사용하는 것은 좋은 방법이 나를

LEFT OUTER JOIN RecipeReviews 
ON RecipeReviews.RecipeId=Recipes.RecipeId 
    AND [email protected] 
    AND RecipeReviews.RecipeRatingId= 
     (SELECT MAX(RecipeReviews.RecipeRatingId) 
     FROM RecipeReviews 
     WHERE [email protected] 
     AND RecipeReviews.RecipeId=FavoriteRecipes.RecipeId) 
     OR RecipeReviews.RecipeRatingId IS NULL 

에게에 관한 것이다. 나는 이것이 당신이 가지고 있을지도 모르는 어떤 지표도 사용하지 않는 것이 강력하다고 생각합니다. 그리고 OR 부분은 그렇지 않습니다. t는 mea atll 모두에게 이해가됩니다. 왼쪽 join은 당신에게 이것을 가져옵니다.

대신 파생 테이블을 만들려면 다시 작성하십시오.

많은 레코드가있는 경우 임시 테이블은 일반적으로 테이블 변수보다 성능이 좋으며 인덱싱 할 수 있어야합니다.

0

내가 처음하는 간단한 일은 모든 선언문을 맨 위로 옮기는 것입니다.

DECLARE @ROW_START INT, 
     @ROW_END INT, 
     @RecipeCount INT 

    DECLARE 
    @RESULT_SET_TABLE 
TABLE 
( 
    Id INT NOT NULL IDENTITY(1,1), 
     ) 

여전히 오히려 간단하다 다음 부분은 다음과 같은 것들이다 :

AND Recipes.RecipeStateId <> 3 
AND RecipeTweaks.TweakedById= @UserId 

이 꺼낼 수있는 가입하고 where 절로 이동합니다. 가능한 경우 인덱스 검색을 utlize 할 수 있도록 in 문으로 <>을 변경하십시오.

AND RecipeReviews.RecipeRatingId= 
( 
    SELECT MAX(RecipeReviews.RecipeRatingId) 
    FROM RecipeReviews 
    WHERE [email protected] 
     AND RecipeReviews.RecipeId=FavoriteRecipes.RecipeId 
) 

나는 미친 찾고있어 완전히 다시해야합니다.