2012-01-30 113 views
0

我有一張表格每晚都被插入,然後作爲報表查詢。SQL Server - 存儲過程性能問題

爲查詢工作的存儲過程具有動態SQL字符串,分頁和其中的兩個臨時表。

它非常適用第一週

從第二週開始,它的性能開始急劇下降(花費3.5分鐘時的恢復)

我已經獲得並運行動態的輸出字符串SQL,它顯着更快(2秒),所以我猜它可能與編譯器相關

然後我做了一些優化,如將count(*)更改爲count(event_id),表現立即回來,但第二天早上表現再次下降。

然後我改變select into明確聲明臨時表,表現馬上回來,但第二天早上表現再次下降。

然後我改變聲明臨時表明確回select into,表現立即回來,但第二天早上表現再次下降。

所以我想它無關代碼優化,似乎每一次SP得到了編譯時間,性能只能爲不到24小時

我想到夜間插入,這是更好也24小時循環,然後我發現這個with (nolock)的事情,這可能已經鎖定了表1

加入Nolock後,該存儲過程運行良好了一個星期,在這之後我們再次得到了同樣的問題,不同的是這一次,只有調用SP的網頁很慢,從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

你能爲我們定義「快」和「慢」嗎?我有需要幾天運行的特效,還有一些會考慮0.5s很慢。 – JNK 2012-01-30 13:08:45

+2

並且在生產代碼中遠離Nolock - 它會導致您錯過已經提交的行。 – 2012-01-30 13:37:09

+0

感謝您的問題。使用相同的數據集時,正常工作需要2秒鐘,如果不正常,需要約3.5分鐘。 – Ree5un 2012-01-30 14:54:02

回答

2

這是有可能的查詢使用創建的統計數據隨着時間的推移,計劃逐漸過時。

考慮在受查詢影響的表上每6小時更新一次統計信息 - 如果可能,請在開發環境中對其進行測試。

0

我建議您在每次sp開始時嘗試使用選項WITH RECOMPILE來刷新執行計劃。

而且存在對於這樣的情況下優化執行計劃的一些技術設備: http://msdn.microsoft.com/en-us/library/ms181714.aspx

例如:

OPTIMIZE FOR 

PARAMETERIZATION 

希望這將有助於。通過

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' 

,不要忘記創建對錶2的索引:

+0

我剛剛添加了一些代碼示例,以查明格式化是否搞亂了,所以請忽略此評論。 – Ree5un 2012-02-14 15:06:31

0

我建議你完全避免動態SQL,您可以替換像這樣的一些代碼.client_id!

+0

感謝您的提示:=) 是的,關於計劃緩存,我正在啓動動態SQL並執行靜態SQL,希望在接下來的兩週內我會回到這裏更新它是否會生效: – Ree5un 2012-02-14 14:57:07

+0

剛剛添加如果你有時間,草案中的草案發生了變化,請幫助我看看,如果有任何問題,謝謝! – Ree5un 2012-02-14 15:15:29

+0

你好, 你的SQL聽起來更好:)如果你的存儲過程沒有返回太多的行,你可以使用內存中的臨時表(http://odetocode.com/code/365.aspx)以避免使用的tempdb數據庫。 要增加應用程序的spped,可以避免在SQL Server中對數據進行排序,並在應用程序端執行該操作。如果您使用.NET平臺,則可以例如實現IComparer接口。 – schglurps 2012-02-14 20:35:39