0

私はすべてを試しましたが、この問題を克服できませんでした。

テーブル値関数があります。

この関数を呼び出すと

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
    )

どんな助けでも大歓迎です。

ありがとう。エムラ

4

1 に答える 1

1

あなたのボトルネックは計算と非常に高価な内部結合だと思います。

あなたが参加している方法は、基本的にクロス結合を作成することです.idが提供されたものを除いて、他のすべてのレコードにリンクされたすべてのレコードを含む結果セットを返します. 次に、他の内部結合を使用してその結果セットに追加します。

すべての内部結合に対して、SQL は実行され、すべての行が一致する結果セットを作成します。したがって、クエリで最初に行うことは、基本的に同じテーブルでクロス結合を行うように SQL に指示することです。(私はあなたがまだフォローしていると仮定しています.

次の内部結合では、結果テーブルを新しく作成した巨大な結果セットに適用し、両方のテーブルではなく結果セットを除外します。

したがって、最初に、結合を逆にできないかどうかを確認してください。(これは実際にテーブルのレコード数とレコード サイズに依存します)。最初に最小の結果セットを取得してから、それに参加してください。

2 番目に試みたいことは、最初に、結合の前であっても結果セットを制限することです。そのため、o1.id = @trackId でフィルタリングする CTE から始めます。次に、この CTE から * を選択し、CTE で結合を行い、o2.id = ISNULL(@nTrackId, o2.id) のクエリでフィルター処理します。

私は例に取り組みます、お楽しみに...

-- OK、例を追加し、簡単なテストを行ったところ、返される値は同じでした。これをデータで実行し、改善があるかどうかをお知らせください。(注: これは、説明した INNER JOIN オーダー ポイントには対応していません。それでも、いじってみてください。)

例:

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 
    ) 
于 2011-12-19T11:20:02.547 に答える