2012-01-19 21 views
2

TableBによって自身に関連するテーブル(TableA)からのデータセットがあります。 TableAの親はTableAの子を持っています。それらの子供には子供もいるかもしれません。ここには素晴らしいものはありません。ストリーミングSQL Server 2008再帰的CTE

私は操作が必要なTableAの行の最上位セットを持っています。私はそれらの行を操作する前に、各子行を手元に置いておく必要があります。私はTableAの各最上位行(およびそれの子供)を私のアプリケーションでできるだけ早く操作できる必要があります。

私はこれを行う方法が見つかりません。

再帰的CTE(TableAアンカーとして最上位セット、TableB->TableA結合として結合)を使用すると、要件を満たしません。 TableAの最上位セット全体が、子のレベル2で動作する前にCTEに返されます。次に、レベル3で動作します。次にレベル4などトップレベルのセットが400,000以上の行であるため、クライアントアプリケーションはサーバー上で全データセットがバッチアップされるまで行の作業を開始できません。

これを行うには、より良い方法が必要です。私はクライアントにトップレベルのTableA行のフラットセットをストリーミングしようとしましたが、クライアントは各最上位のTableA行に対して繰り返しCTE文を繰り返し発行していました。これは実際に動作します。しかし、あまりにも多くのノイズがあります。文の再発行が繰り返されるため、持続的な行検索率が大きすぎます。

私は創造的な解決策が必要です。

レコードごとのCTEのスニペットを使用しています。この例では、TableAはMemberであり、TableBはMemberReplacementです。私は途中でselectステートメントのほとんどと、ほとんどの結合を取り除いた。

WITH T_MemberRecurse 
(
    MemberId, 
    IncludedMemberId, 
    Level 
) AS (
    SELECT  Member.Id, 
       Member.Id, 
       0 
    FROM  MemberInput 
    INNER JOIN MemberInputItem 
     ON  MemberInputItem.MemberInputId = MemberInput.Id 
    INNER JOIN Member 
     ON  Member.Id = MemberInputItem.MemberId 
    UNION ALL 
    SELECT  T_MemberRecurse.MemberId, 
       Member2.Id, 
       Level + 1 
    FROM  T_MemberRecurse 
    INNER JOIN Member 
     ON  Member.Id = T_MemberRecurse.IncludedMemberId 
    INNER JOIN MemberReplacement 
     ON  MemberReplacement.MemberId = Member.Id 
    INNER JOIN Member Member2 
     ON  Member2.Id = MemberReplacement.OriginalMemberId 
) 
SELECT  Member.Id, 
      T_MemberRecurse.IncludedMemberId, 
      T_MemberRecurse.Level, 

FROM  MemberInput 
INNER JOIN LotsOfTables 
+0

サンプルコードとサンプルデータを投稿できますか? – JNK

+0

しました。レコードごとのCTEの例を追加しました。この例を掲示する際の問題は、私の例のどれもが問題を解決するために設計されていないことです。 – wasabi

+0

申し訳ありません、* '設計されていません' * - それはどういう意味ですか?現在のソリューションが間違った結果を返すのか、単に効率的でないのか? –

答えて

1

私は今このことについて少し考えて、私は行ごとの操作を強制的にすることで、パフォーマンスを改善し、リンクサーバーで持っていた経験のために役立つかもしれない暗闇の中で最初に刺し、よ2桁の大きさ。

CTEを、1つのパラメータ、必要なメンバーIDを持つ行セットを返す関数に変換します。その後

SELECT 
    * 
FROM 
    Member M 
    CROSS APPLY dbo.MemberChildren(M.Id) C 
WHERE 
    {Conditions for desired set of Members here} 
WITH (FAST 20); 

これが動作するかどうか私に教えてください。このアイデアは、エンジンをワイドファーストではなく深みのあるものにするように強制することです。理論的には、クライアントがいくつかのデータ行で作業を開始できるようにする必要があります。

更新

第二のアイデア:マージはクライアントに参加し、論理的に、個別に親と子の情報を取得し、実行します。 (順不同になるまで順番に並んだ2番目の/内側の入力だけを進める順序付けられたネストされたループ)キー範囲またはrow_numberを使用して一度に小さなチャンクを取得します。または、親セット全体を取得し、子ローのより小さなセットを取得します。

アップデート2

アイデア3:代わりに再帰CTEの、5プレーンバニラを使用し、あなたが必要なすべてのデータを取得するために結合します。それは恐ろしいと思うが、データを始めるためにFAST 100をやらなければならない。

+0

Hmm。それはうまくいくかもしれない。それを達成するために関数を宣言することを避けようとしていましたが、これは適切であり、うまくいくかもしれません。私は月曜日にそれをやります。 – wasabi

+0

外部参照を含むサブクエリーに適用されるクロスリファレンスは、理論的には深く先に進むことができますが、そうでないかもしれません。従って関数。 – ErikE

+0

CTEをサブセレクトに入れることができたら、しばらく前に解決していたでしょう。 =/ – wasabi

関連する問題