2011-12-19 5 views
0

모든 것을 시도했지만이 문제를 해결할 수 없습니다.SQL Server 테이블 반환 함수는 느린 처리 ​​

테이블 값 기능이 있습니다. 제가

SELECT * FROM Ratings o1 
    CROSS APPLY dbo.FN_RatingSimilarity(50, 497664, 'Cosine') o2 
WHERE o1.trackId = 497664 

이 함수를 호출 할 때

그것은 실행되는 동안 소요. 그러나 내가 이것을 할 때.

SELECT * FROM Ratings o1 
    CROSS APPLY dbo.FN_RatingSimilarity(50, o1.trackId, 'Cosine') o2 
WHERE o1.trackId = 497664 

32 초 후에 실행됩니다. 모든 색인을 만들었지 만 도움이되지 않았습니다. 그런데

내 기능 : 어떤 도움을 주시면 감사하겠습니다

ALTER FUNCTION [dbo].[FN_RatingSimilarity] 
( 
    @trackId INT, 
    @nTrackId INT, 
    @measureType VARCHAR(100) 
) 
RETURNS TABLE 
WITH SCHEMABINDING 
AS 
    RETURN 
    (
     SELECT o2.id, 
       o2.name, 
       o2.releaseDate, 
       o2.numberOfRatings, 
       o2.averageRating, 
       COUNT(1) as numberOfSharedUsers, 
      CASE @measureType 
       WHEN 'Cosine' THEN SUM(o3.score*o4.score)/(0.01+SQRT(SUM(POWER(o3.score,2))) * SQRT(SUM(POWER(o4.score,2)))) 
       WHEN 'AdjustedCosine' THEN SUM((o3.score-o5.averageRating)*(o4.score-o5.averageRating))/(0.01+SQRT(SUM(POWER(o3.score-o5.averageRating, 2)))*SQRT(SUM(POWER(o4.score-o5.averageRating, 2)))) 
       WHEN 'Pearson' THEN SUM((o3.score-o1.averageRating)*(o4.score-o2.averageRating))/(0.01+SQRT(SUM(POWER(o3.score-o1.averageRating, 2)))*SQRT(SUM(POWER(o4.score-o2.averageRating, 2)))) 
      END as similarityRatio 
      FROM dbo.Tracks o1 
    INNER JOIN dbo.Tracks o2 ON o2.id != @trackId 
    INNER JOIN dbo.Ratings o3 ON o3.trackId = o1.id 
    INNER JOIN dbo.Ratings o4 ON o4.trackId = o2.id AND o4.userId = o3.userId 
    INNER JOIN dbo.Users o5 ON o5.id = o4.userId 
     WHERE o1.id = @trackId 
      AND o2.id = ISNULL(@nTrackId, o2.id) 
     GROUP BY o2.id, 
       o2.name, 
       o2.releaseDate, 
       o2.numberOfRatings, 
       o2.averageRating 
    ) 

.

감사합니다. Emrah

+1

질문이 무엇인지 확실하지? 당신이 제공하는 2 개의 코드 샘플은 다른 일을합니다. 첫 번째 매개 변수에는 상관 된 매개 변수가없고 쉽게 다시 작성할 수 있지만 두 번째 매개 변수는 쉽게 다시 작성할 수 있습니다. 아마도 두 경우 모두 함수가 외부 행에서 호출되고 두 번째 행에 WHERE 절이 있기 때문에 이것은 더 작은 숫자 일 것입니다. –

+0

죄송합니다. 나는 틀린 질문을 썼다. – emrahyigit

답변

1

저는 병목 현상이 계산 + 매우 비싼 내부 조인이라고 생각합니다.

기본적으로 교차 조인을 만드는 방식입니다. 모든 레코드가 다른 모든 레코드에 링크 된 결과 세트가 반환됩니다. id가 제공된 레코드는 제외하고. 그런 다음 다른 내부 조인과 함께 결과 세트에 추가합니다.

모든 내부 조인에 대해 SQL은 모든 행이 일치하는 결과 집합을 만들고 이동합니다. 쿼리에서 가장 먼저해야 할 일은 기본적으로 동일한 테이블에서 교차 조인을 수행하도록 SQL에 지시하는 것입니다. (나는 여전히 당신이 따르고 있다고 가정하고 꽤 고급스러워서 고급 SQL 문법과 연산자에 익숙하다.)

이제 다음 내부 조인에서 새로 생성 된 테이블에 결과 테이블을 적용한다. 거대한 결과 세트를 생성 한 다음 두 테이블이 아닌 모든 테이블을 필터링합니다.

처음에는 다른 방향으로 조인을 할 수 없는지 확인하십시오. (이것은 실제로 테이블 레코드 수와 레코드 크기에 달려 있습니다.) 가장 작은 결과 세트를 먼저 가져 와서 그 위에 결합하십시오.

두 번째로 시도해보고 싶은 것은 조인 이전에 결과 집합을 제한하는 것입니다. 따라서 o1.id = @trackId를 필터링하는 CTE로 시작하십시오. 그런 다음이 CTE에서 *를 선택하고 CTE에서 조인을 한 다음 o2.id = ISNULL (@nTrackId, o2.id)에 대한 필터를 필터링하십시오.

예를 들어서 ... 계속 하시겠습니까?

- 예를 들어, 빠른 테스트를 수행했는데 반환 된 값이 같습니다. 귀하의 데이터를 통해 이것을 실행하고 어떤 개선이 있는지 알려주십시오.

예. (참고,이, 아직도 그와 함께 놀러 않습니다 논의 INNER 조인 순서 점을 언급하지 않음) :

ALTER FUNCTION [dbo].[FN_RatingSimilarity_NEW] 
( 
    @trackId INT, 
    @nTrackId INT, 
    @measureType VARCHAR(100) 
) 
RETURNS TABLE 
WITH SCHEMABINDING 
AS 
    RETURN 
    ( 
     WITH CTE_ALL AS 
     (
      SELECT id, 
       name, 
       releaseDate, 
       numberOfRatings, 
       averageRating 
      FROM dbo.Tracks 
      WHERE id = @trackId 
     ) 
     SELECT o2.id, 
       o2.name, 
       o2.releaseDate, 
       o2.numberOfRatings, 
       o2.averageRating, 
       COUNT(1) as numberOfSharedUsers, 
      CASE @measureType 
       WHEN 'Cosine' THEN SUM(o3.score*o4.score)/(0.01+SQRT(SUM(POWER(o3.score,2))) * SQRT(SUM(POWER(o4.score,2)))) 
       WHEN 'AdjustedCosine' THEN SUM((o3.score-o5.averageRating)*(o4.score-o5.averageRating))/(0.01+SQRT(SUM(POWER(o3.score-o5.averageRating, 2)))*SQRT(SUM(POWER(o4.score-o5.averageRating, 2)))) 
       WHEN 'Pearson' THEN SUM((o3.score-o1.averageRating)*(o4.score-o2.averageRating))/(0.01+SQRT(SUM(POWER(o3.score-o1.averageRating, 2)))*SQRT(SUM(POWER(o4.score-o2.averageRating, 2)))) 
      END as similarityRatio 
      FROM CTE_ALL o1 
    INNER JOIN dbo.Tracks o2 ON o2.id != @trackId 
    INNER JOIN dbo.Ratings o3 ON o3.trackId = o1.id 
    INNER JOIN dbo.Ratings o4 ON o4.trackId = o2.id AND o4.userId = o3.userId 
    INNER JOIN dbo.Users o5 ON o5.id = o4.userId 
     WHERE o2.id = ISNULL(@nTrackId, o2.id) 
     GROUP BY o2.id, 
       o2.name, 
       o2.releaseDate, 
       o2.numberOfRatings, 
       o2.averageRating 
    ) 
+0

죄송합니다. 질문을 쓰는 동안 실수를했습니다. 이제 업데이트했습니다. 도와 주셔서 감사합니다. – emrahyigit

+0

두 벡터 사이의 유사성 측정 값을 찾으려고합니다. 이 두 벡터는 일반 사용자가 평가 한 두 항목의 등급입니다. – emrahyigit

+0

이제는 실제 문제에 집중할 수 있습니다. -> 느린 성능. 내 업데이트 된 답변을 1 분 정도 참조하십시오 ... – Charl