0

実行に約15時間かかるスクリプトを作成しました。このスクリプトをできるだけ速くするために、クエリ最適化の手法や提案が必要です...誰か助けてくれる人がいたら、スクリプトを見てください。

declare @max_date date
declare @client_bp_id int

Select @max_date=MAX(tran_date) from All_Share_Txn

DELETE FROM Client_Share_Balance

DECLARE All_Client_Bp_Id CURSOR FOR
SELECT Bp_id FROM  Client       --Take All Client's BPID 
    OPEN All_Client_Bp_Id
    FETCH NEXT FROM All_Client_Bp_Id
        INTO @client_bp_id
    WHILE @@FETCH_STATUS = 0
    BEGIN

    Insert Client_Share_Balance(Bp_id,Instrument_Id,Quantity_Total,Quantity_Matured,Quantity_Pledge,AVG_Cost,Updated_At,Created_At,Company_Id,Created_By,Updated_By)
    select @client_bp_id,Instrument_Id,
       sum(case when Is_buy='True' then Quantity when Is_buy='False'  then -quantity end), --as Total Quantity
       sum(case when Mature_Date_Share <= @max_date then (case Is_buy when '1' then quantity when '0' then -quantity end) else 0 end),  --as Free Qty
       ISnull((select sum(case pu.IsBuy when '1' then -pu.quantity else pu.quantity end) from
            (Select * from Pledge UNION Select * from Unpledge) pu
                where pu.Client_Bp_id=@client_bp_id and pu.Instrument_Id=t1.Instrument_Id and pu.Txn_Date<=@max_date
                group by pu.Client_Bp_id,pu.Instrument_Id),0),  -- as Pledge_Quantity
       dbo.Avg_Cost(@client_bp_id,Instrument_Id), --as Avg_rate
       GETDATE(),GETDATE(),309,1,1

    from All_Share_Txn t1
    where Client_Bp_id=@client_bp_id and Instrument_Id is not null 
    group by Instrument_Id
    having sum(case Is_buy when '1' then quantity when '0' then -quantity end)<> 0
    or sum(case when Mature_Date_Share <= @max_date then (case Is_buy when '1' then quantity when '0' then -quantity end) else 0 end) <> 0

    FETCH NEXT FROM All_Client_Bp_Id
        INTO @client_bp_id

END

CLOSE All_Client_Bp_Id
DEALLOCATE All_Client_Bp_Id

コードをより効率的に記述できるかどうかを確認する必要があります。

4

3 に答える 3

2

私があなたのコードを理解しているなら。カーソルはコードのボトルネックです。だから私はカーソルをスキップして次のようなことをします:

Insert Client_Share_Balance(Bp_id,Instrument_Id..)
select Client_Bp_id,
......
from All_Share_Txn t1
where EXISTS(SELECT NULL FROM Client WHERE Client_Bp_id=t1.Bp_id) 
and Instrument_Id is not null 
group by Instrument_Id,Client_Bp_id
.......
于 2012-05-15T14:08:49.273 に答える
2
  1. *をColumnNamesに置き換えますSelect * from Pledge。それは次のようになります
    Select Instrument_Id from Pledge

  2. カーソルの使用を除外します。

  3. 一意のレコードがPledgeありますか。Unpledgeある場合は、テーブルをUNION ALL使用する必要があります。と比較して速いのでUNION

  4. のレコードをAll_Share_Txnに挿入しLocal Temporary Tableます。

  5. Local Temporary tableInstrument_Id列とに基づいてフィールド「合計数量」情報を持つ別のファイルを作成しますInstrument_Id。次に、Switchケースベースの条件を評価し、このテーブルに数量情報のレコードを挿入します。このコンテキストの情報を抽出するときは、手順3で作成したローカル一時テーブルを使用することに注意してください。

  6. Local Temporary tableInstrument_Id列とに基づいて「FreeQty」情報のフィールドを持つ別のファイルを作成しますInstrument_Id。次に、Switchケースベースの条件を評価しFree Qty、このテーブルに情報のレコードを挿入します。このコンテキストの情報を抽出するときは、手順3で作成したローカル一時テーブルを使用することに注意してください。

  7. Local Temporary tableInstrument_Id列とに基づいてフィールド'Pledge_Quantity'情報を持つ別のものを作成しますInstrument_Id。次に、Switchケースベースの条件を評価しPledge_Quantity、このテーブルに情報のレコードを挿入します。このコンテキストの情報を抽出するときは、手順3で作成したローカル一時テーブルを使用することに注意してください。

  8. Local Temporary tableInstrument_Id列とに基づいてフィールド'Avg_rate'情報を持つ別のものを作成しますInstrument_Id。次に、Switchケースベースの条件を評価しAvg_rate、このテーブルに情報のレコードを挿入します。このコンテキストの情報を抽出するときは、手順3で作成したローカル一時テーブルを使用することに注意してください。

  9. ここで、ステップ3、4、5、6、7で作成されたテーブル間の結合を使用して、結果セットを即座に取得できます。

于 2012-05-15T18:43:04.550 に答える
0

COMMITTEDデータを読み取っていることを気にしない限り、オブジェクトをロックせずに、SQL Serverにデータをそのまま表示するように指示できます...基本的にWITH(NOLOCK)と同じ動作ですが、Microsoftでは使用しないことをお勧めします。オブジェクトのヒントと、SQLServerに使用する最適なロック方法を決定させる。データがコミットされているかどうかを「心配」することなく、これによりデータのフェッチが大幅に高速化されます。

これをクエリの先頭に追加します

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED--接続レベルで設定します。一度だけではありません。

このリンクを参照してくださいトランザクション分離レベル

次に、クラスター化インデックスが含まれている一意のID列を確認してください。固有の制約がある場合でも、テーブルではなくヒープが残ります。ヒープは基本的に散在する混乱です。(おそらく、このことを知っているでしょう。言及するだけです)次に、WHERE ORDER BY GROUP HAVING ...で使用するすべての列に非クラスター化インデックスがあり、頻繁に返される列が含まれていることを確認します。これは、より多くのディスクスペースを消費します。Enterpriseバージョン以降を使用している場合は、圧縮されたインデックスとテーブルを使用してください。

テーブルに対してUPDATESTATISTICSWITH FULLSCANを実行して、SQLServerに最新かつ最高の統計を提供します。ちなみに、クラスター化されたインデックスを再構築すると、これが自動的に行われます。また、テーブルが数百万行の場合は時間がかかる可能性があるため、データ統計のみを更新してこのプロセスを高速化するように指示できます。

あなたが受けている最大のパフォーマンスヒットは、集計された結果でグループ化しているという事実です。SQL Serverは、スキャン、作業テーブルの使用、並べ替えなどを行いますが、すべてがインデックスを探します。これは、GROUP BY、HAVINGなどに使用するインデックスがないためです。

この問題で選択の余地がない場合もありますが、#temporaryテーブル(またはテーブルオブジェクト。両方にインデックスを作成できます)を作成し、事前に計算された結果を入力して、この#temporaryテーブルが参加する。ORDER BY、GROUP BY、HAVINGを使用する場合、1つの列、または複数の列を使用していて、SUMやスカラー値のユーザー定義関数などの集計を使用しない限り、低速になります。あなたはそれがもっと速いはずだと思うと述べました。

SQLServerのインスタンスを確認するためのいくつかの基本設定:

  1. tempdbには、コアと同じ数のファイルがあり、すべて同じサイズで、%ではなくMBを使用したすべて同じ成長率である必要があります。コアが8つを超える場合は、最大8つのファイルになります。変更を加えた後、インスタンスを再起動します。あなたはしなければなりませんが、私はそれをお勧めします。

    例:12コア。

    tempdb.mdf      size= 1024MB   growby= 256MB
    tempdb2.ndf  size= 1024MB   growby= 256MB
    (etc)
    tempdb8.ndf size= 1024MB   growby= 256MB
    
  2. データベースと同じです。さらにファイルを追加する必要がある場合は、推奨サイズ設定を使用して追加し、すべてのクラスター化インデックスを再構築します。これにより、データの物理構造が再構築されるため、データがファイル全体に分散されます。

  3. SQLServerにすべてのメモリを占有させないでください。制限をtotal_avail_phys_memoryから2GBを引いた値に設定します(O / Sに十分な量のメモリを残します)

  4. PRIMARYFILEGROUPを使用するだけではありません。データとインデックスを独自のファイルグループに分けます。可能であれば、RAID 10ドライブにインデックスを配置し、RAID5または6にデータを配置します。

  5. SQL Serverユーザーデータベースに、メンテナンスプランを使用した定期メンテナンス、または独自のスクリプトのロールによって、必要なケアを提供していることを確認してください。

  6. RAID 5のデータ、RAID 10のログ、RAID 10のTempdb-各LUN(ドライブ文字)には専用のスピンドル(ドライブ)が必要です

これらの提案が、インスタンスの全体的なパフォーマンスに役立つと思われる場合は、役立つことを願っています。

于 2012-07-06T04:53:37.013 に答える