2012-01-30 16 views
0

私は毎晩挿入され、レポートテーブルとしてクエリされるテーブルを持っています。SQL Serverストアドプロシージャのパフォーマンス問題

クエリで機能するストアドプロシージャには、動的SQL文字列、ページング、および2つの一時テーブルがあります。

それは第二週から始まって最初の週

に適しています

は、その性能が急激に低下し始める私が取得した

(戻るには3.5分かかります)、その後、ダイナミックの出力文字列を実行しますSQLは劇的に高速(2秒)ですので、コンパイラに関連する可能性があります

count(*)count(event_id)に変更するような最適化を行いましたが、パフォーマンスはただちに戻りますが、翌朝パフォーマンスが再び低下します。

次に、select intoを明示的にtempテーブルに変更したところ、パフォーマンスはただちに戻りましたが、翌朝パフォーマンスが再び低下しました。

次に、テンポラリテーブルを明示的にselect intoに戻して変更しました。パフォーマンスはただちに戻りますが、翌朝パフォーマンスが再び低下します。

だから私はそれは、コードの最適化とは何の関係もないと思いますが、それはSPがコンパイルされてしまったたびに思える、パフォーマンスは私が毎晩挿入、考えています唯一の24時間未満

のために改善することができますまた、私はこれを見つけたwith (nolock)は、ロックされていた可能性がありますテーブル

Nolockを追加した後、 SPを呼び出しているWebページだけが遅く、DBからSPを実行すると高速です...

ここ

は、動的SQLストアドプロシージャです:

CREATE PROCEDURE [dbo].[fs_1_usp_query] 
@paramerter_client_id int = null, 
@paramerter_event_type_id int = null, 
@paramerter_start_date   datetime = null, 
@paramerter_end_date   datetime = null, 
@paramerter_page_index int = 1, 
@paramerter_sort_direction varchar(20), 
@paramerter_page_count int = 30 
AS 
BEGIN  
SET ARITHABORT ON; 
SET NOCOUNT ON; 

declare @sql nvarchar(max) 

set @sql =  ' 

    create table #output2  
    ( 
      page_index          int,  
       rownumber           int, 
      page_count       int,  
      client_id       int,  
      date           datetime, 
    ) 




     --insert into #output1 
    select 
    page_count = count(event_id) over(),  
    table1.* 
    into #output1' 
    set @sql = @sql + ' 
    from 
    table1 table1 with (nolock) 
    inner join 
    table2 table2 with (nolock) 
    on 
    ............................ 
    inner join 
    table3 table3 with (nolock) 
    on 
    ............................ 
    inner join 
    table4 table4 
    on 
    ............................ 
    where 
    ............................ 

if (@paramerter_client_id is not null) 
    set @sql = @sql + ' and table2.client_id = @paramerter_client_id' 

if (@paramerter_event_type_id is not null) 
    set @sql = @sql + ' and table2.event_type_id = @paramerter_event_type_id' 

if (@paramerter_start_date is not null) 
    set @sql = @sql + ' and table2.created_date >= @paramerter_start_date' 
if (@paramerter_end_date is not null) 
     set @sql = @sql + ' and table2.created_date <= @paramerter_end_date' 

declare @lv_begin_index int 
declare @lv_end_index int 
set @lv_begin_index = ((@paramerter_page_index - 1) * @paramerter_page_count) + 1  
set @lv_end_index = @lv_begin_index + @paramerter_page_count  

set @sql = @sql + ' 

UPDATE #output1 
    SET osat_rating = ''-'' 
    WHERE LEFT(osat_rating , 1) = ''-''   

insert into #output2 
select  
    page_index = ' + convert(varchar, @paramerter_page_index) + ',  
    row_number() over (order by [' + @paramerter_sort_expression + '] '+ @paramerter_sort_direction + ') as rownumber, 
    #output1.* 
from #output1 

select #output2.* 
from #output2 
where 
    rownumber >= ' + convert(varchar, @lv_begin_index) + ' 
and 
    rownumber < ' + convert(varchar, @lv_end_index) ' 

set @sql = @sql + '  
drop table #output1  
drop table #output2 '* 

ここでご提案に従うための試みとして、静的SQLのスナップショットです:

Where 
    Column3 = Coalesce(@parameter3, Column3) 
    and 
    (@start_date is null or Column_created_date >= @start_date) 

    and 
    (@param_1 is null 
      or 
       (@param_1 not in (‘ConstantString1’, 'ConstantString2') and Column1 = @param_1) 
     or 
      (@param_1 = ‘ConstantString1’ and Column1 like 'ConstantString1%') 
     or 
      (@param_1 = ‘ConstantString2’ and (Column1 is null or Column1 = '')) 
) 
If(@parameter_sort_direction = 'DESC') 
Begin 
    insert into #temp_table_result 
    select  
     page_index = convert(varchar, @parameter_page_index),   
     row_number() over 
     (
      order by CASE 
        WHEN @parameter_sort_expression = 'Column1' THEN Column1 
        WHEN @parameter_sort_expression = 'Column2' THEN Column2 
        WHEN @parameter_sort_expression = 'Column3' THEN Column3 
        WHEN @parameter_sort_expression = 'Column4' THEN Column4 
        WHEN @parameter_sort_expression = 'Column5' THEN Column5 
        WHEN @parameter_sort_expression = 'Column6' THEN Column6 
        WHEN @parameter_sort_expression = 'Column7' THEN Column7 
        WHEN @parameter_sort_expression = 'Column8' THEN Column8 
       END desc--CASE 
       --  WHEN @parameter_sort_direction = 'ASC' THEN asc 
       --  WHEN @parameter_sort_expression = 'DESC' THEN  desc    
       --END 
     ) as rownumber, 
     #temp_table_staging.* 
    from #temp_table_staging 
END 
+1

"高速"と "低速"を定義できますか?私は走るのに数日かかるプロクセスがありますが、それは遅すぎると考えるものがあります。 – JNK

+2

そして、生産コードでNolockから離れてください - あなたが既にコミットされた行を見逃す可能性があります。 –

+0

ご質問ありがとうございます。同じデータセットでは、正常に動作している場合は2秒、問題でない場合は約3.5分かかります。 – Ree5un

答えて

2

それはそうなクエリが作成するために使用される統計です計画が徐々に時代遅れになってきています。

クエリの影響を受けるテーブルで6時間ごとに統計情報を更新することを検討してください。可能であれば、これを開発環境でテストしてください。

0

sp起動時に実行プランを更新するには、WITH RECOMPILEオプションを使用することをお勧めします。

そして、このような場合のために最適化実行計画のためのいくつかのより多くのテクニクスがあります。たとえば http://msdn.microsoft.com/en-us/library/ms181714.aspx

OPTIMIZE FOR 

または

PARAMETERIZATION 

希望に役立ちます。 table2のにインデックスを作成することを忘れないでください、もちろん

and (@paramerter_client_id IS NULL OR table2.client_id = @paramerter_client_id) 

によって

 if (@paramerter_client_id is not null) 
     set @sql = @sql + ' and table2.client_id = @paramerter_client_id' 

:私はあなたが完全に動的SQLを避けるためにお勧め

+0

私は、コードのいくつかの例を追加して、フォーマットが乱れていることを確認しました。このコメントは無視してください。 – Ree5un

0

は、あなたがこのようないくつかのコードを置き換えることができます。クライアントID !

+0

アドバイスありがとう:=) プラン・キャッシングに関して、私は動的SQLを取り除き、静的SQLを実行しています。うまくいけば、これがうまくいくかどうかをアップデートしてここに戻ります: – Ree5un

+0

ちょうど追加あなたが時間があれば、それは何か間違っている場合は、親切に私は一見を助けてください、ありがとう! – Ree5un

+0

こんにちは SQLの方がいいです:)ストアドプロシージャがあまりにも多くの行を返さない場合は、使用を避けるためにメモリ内のテンポラリテーブル(http://odetocode.com/code/365.aspx)を使用できますtempdbデータベースの。 アプリケーションのサイズを増やすには、SQL Serverでデータを並べ替えるのを避け、アプリケーション側で行うことを避けてください。 .NETプラットフォームを使用する場合は、たとえばIComparerインターフェイスを実装できます。 – schglurps

関連する問題