2

さまざまな情報を返すために約 90,000 レコードを処理するために使用されるストアド プロシージャがあります。これは、実行するレコードをフィルター処理するために SQL テーブルに参加するだけです (これは、vb.net バッチが使用する前に別のプロセスから読み込まれます)。ここで、Windows アプリケーションを介して個々の人のために実行できる 90,000 人のストアド プロシージャとまったく同じロジックを用意する必要があります。私の最初の考えは、同じストアド プロシージャを使用し (ロジックを複製しないため)、次のいずれかをロード/使用する一時テーブル変数を持つことでした: -- 渡された memberID (Windows アプリ経由の場合) または -- 90,000 メンバーを含むテーブル (memberID が渡されず、バッチから呼び出された場合)。私の懸念は、個々の行に使用される場合もあれば、90,000 行に使用される場合もある場合に、クエリ プランにどのような影響があるかということです。パフォーマンスと効率はどのように影響を受けますか? これは良い考えですか?それとも、重複したロジックを持つ別のストアド プロシージャにする必要がありますか?

**以下は、私が話していることの詳細です。私はそれを単純化しようとしましたが、オンラインで表示するためにすべての名前を変更する必要がありました.

--===========================================================================================
--The first query is getting all the members information for the batch run.
--It is joining to a tmpMembers table which is loaded with the members for the batch run 
--(filtering it down to approxiately 90,000 members for that batch run)

CREATE PROCEDURE s_GetMembersInfoSEL
AS
SELECT * --Includes a great deal of output (some of which is calculated before being returned)
FROM Members m 
INNER JOIN tmpMembers tm
  ON tm.MbrID = m.MbrID
--Also a bunch of other joins to member, claim, service, etc tables for the additional info.  

--===========================================================================================

--Proposed changes...

CREATE PROCEDURE s_GetMembersInfoSEL
                            @MbrID INT = NULL
AS
DECLARE @MbrsTable TABLE (MbrID INT  PRIMARY KEY)

IF @MbrID IS NULL
  BEGIN 
    INSERT INTO @MbrsTable          
    SELECT MbrID
    FROM tmpMembers
  END
ELSE
  BEGIN 
    INSERT INTO @MbrsTable
                (MbrID)         
    VALUES (@MbrID)
  END  

SELECT * --Includes a great deal of output (some of which is calculated before being returned)
FROM Members m 
INNER JOIN @MbrsTable tm
  ON tm.MbrID = m.MbrID
--Also a bunch of other joins to member, claim, service, etc tables for the additional info.  
4

1 に答える 1

1

テーブル変数の使用方法によっては、非効率的なプランが使用される可能性があります。

記事Query performance and table variablesから:

テーブル変数を含むバッチまたはストアド プロシージャがコンパイルされるとき、テーブル変数の行数は不明です。したがって、オプティマイザーはいくつかの仮定を行う必要があります。 テーブル変数の行数が非常に少ないと推定されます。これにより、非効率的な計画が発生する可能性があります。 ほとんどの場合、ネストされたループ結合は、テーブル変数を外部テーブルとして使用します。テーブル変数に多数の行が存在する場合、これにより内部テーブルが何度も実行されます。

...

テーブル変数に入力する行数が多い場合は、この解決策を検討してください。 オプション recompile を、他のテーブルと結合するテーブル変数を含むステートメントに追加できます。これにより、SQL Server は再コンパイル時に行数を検出できるようになります。これは、行が既に取り込まれているためです。 このオプションは、SQL Server 2005 以降でのみ使用できます。

(強調を追加)

更新されたクエリは次のようになります。

SELECT *
FROM Members m 
INNER JOIN @MbrsTable tm
  ON tm.MbrID = m.MbrID
OPTION (RECOMPILE)

ただし、ストアド プロシージャが頻繁に実行される場合、再コンパイルによってパフォーマンスの問題が発生する可能性があることに注意してください。この場合、ビューやユーザー定義関数を使用するなど、このロジックを統合する別の方法を検討し、これら 2 つの異なるシナリオを別々のクエリに分割して、テーブル変数の使用を避けることができます。

于 2012-12-10T17:01:30.070 に答える