2011-12-19 12 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秒で実行されます。私はすべてのインデックスを作成しましたが、それは助けになりませんでした。道による

My機能:任意の助けをいただければ幸いです

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つのコードサンプルは、異なることを行います。最初のものは、任意の相関パラメータを持っていない2つ目はんが容易に書き換えることができます。おそらく、両方の場合において、関数は、外側の列ごとに呼び出され、2番目のいずれかで 'WHERE'句を持っているように、これはわずかに小さい数です。 –

+0

すみません。私は間違った質問を書いて更新しました。 – emrahyigit

答えて

1

私はあなたのボトルネックが計算+非常に高価な内部結合であると信じています。

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

すべての内部結合に対して、SQLはすべての行が一致する結果セットを作成して作成します。 クエリで最初に行うことは、基本的に同じテーブルでクロスジョインを行うようにSQLに指示することです。 (私はまだあなたが従っていると仮定しています。かなり高度なので、高度なSQL構文と演算子に精通しています)

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

まず始めに、あなたは他の方法で結合を行うことができないかどうかを確認してください。 (これは実際にあなたのテーブルレコード数とレコードサイズに依存します)。最小の結果セットを最初に作成してから、それに結合してください。あなたがしようとする場合があります

2つ目は、まずjoins.Soはあなたが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 
    ) 
+0

申し訳ありませんが質問を書いている間に間違いました。今更新しました。手伝ってくれてありがとう。 – emrahyigit

+0

私は2つのベクトル間の類似度を見出そうとしています。これらの2つのベクトルは、共通のユーザーによって評価された2つのアイテムの評価です。 – emrahyigit

+0

さて、実際の問題に焦点を当てることができます; - >パフォーマンスが遅いです。私の更新された回答を1分程度でご覧ください。 – Charl

関連する問題