2015-03-03 69 views
1

我有問題找出爲什麼一個查詢要花費更長的時間運行基於我換出一個參數與真實值。SQL查詢執行使用參數

DECLARE @quarter int 
DECLARE @year int 
DECLARE @countOfUnitsBought int 

set @year = 2009 
set @quarter = 1 
set @countOfUnitsBought = 4; 

with res 
as 
(
select 
o.account_id 
--,orderyear 
--,orderquarter  
from 
fmtables.[dbo].[orders] o  
--cross apply(values(year(o.[ship_date]))) as a1(orderyear) 
--cross apply(values(DatePart(quarter,(o.[ship_date])))) as a2(orderquarter)  
where 
    ship_date = (select min(ship_date) from fmtables.[dbo].[orders] mo where [account_id] = o.account_id) and 
    total_value > 0 AND 
    order_status NOT LIKE 'return%' AND 
    order_status NOT LIKE 'cancel%' AND 
    order_status NOT LIKE 'freeze%' and 
    CAST(DatePart(quarter,(o.[ship_date])) as int) = @quarter and 
    year(o.[ship_date]) = @year and 
    (select sum(quantity) from fmtables..[orders] ox inner join fmtables..[orderlines] olx on ox.order_id = olx.order_id 
         where olx.order_id = o.order_id and [product_code] in(select [product_code] from fmtables..[products] where [category_code] in('1','2','3','4'))) >= @countOfUnitsBought 

) 
select * from res; 

此查詢需要43秒才能運行。

現在,如果我只需更換@quarter和改變文字

CAST(DatePart(quarter,(o.[ship_date])) as int) = 1 and 

現在只需1秒。

任何人都可以請給我一個線索,爲什麼,如果我需要改變一些鑄件來幫助。 感謝 斯科特

編輯:

所以我設法得到它嗖嗖通過與大家的意見幫助。 我使用了從輸入中傳遞參數,然後通過過程中的「本地」變量的混合。

alter procedure [dbo].[Lifetime_HeadsetUnits] 
@inquarter int , @inyear int, @incountOfUnitsBought int 
as 
DECLARE @quarter int 
DECLARE @year int 
declare @countOfUnitsBought int 

select @quarter = @inquarter 
select @year = @inyear 
select @countOfUnitsBought = @incountOfUnitsBought 

並且還 OPTION(OPTIMIZE FOR(@quarter = 1))
作爲最終輸出查詢的一部分。

+1

解決相同的問題在這裏描述:http://stackoverflow.com/questions/11119432/parameter-doesnt-perform-as-well-as-hard-coding-the-value - 你可能會開始通過嘗試'OPTION(OPTIMIZE FOR(@quarter = 1))' – 2015-03-03 13:53:45

+0

您是否知道如何查看查詢計劃?如果這是你真正的疑問,而不僅僅是爲了這個問題的演示,那麼看到兩種選擇之間的區別不應該太難。 – 2015-03-03 13:55:51

+0

@quarter的值將隨着它進入一個循環而改變。我會看看選項設置。謝謝 – scottsanpedro 2015-03-03 13:59:03

回答

1

試試這個。我重寫了日期部分,因此可以使用索引,並且數據庫不會對所有行進行長時間計算。換句話說,我做了你的日期計算sargable

DECLARE @quarter int 
DECLARE @year int 
DECLARE @countOfUnitsBought int 

set @year = 2009 
set @quarter = 1 
declare @from datetime = dateadd(quarter, @quarter - 1, cast(@year as char(4))) 

set @countOfUnitsBought = 4; 

with res 
as 
(
    select 
    o.account_id 
    from 
    fmtables.[dbo].[orders] o  
    where 
    ship_date = 
     (select min(ship_date) 
     from fmtables.[dbo].[orders] mo 
     where [account_id] = o.account_id) and 
    total_value > 0 AND 
    order_status NOT LIKE 'return%' AND 
    order_status NOT LIKE 'cancel%' AND 
    order_status NOT LIKE 'freeze%' and 
    o.[ship_date] >= @quarter and 
    o.[ship_date] < DATEADD(QUARTER, 1, @from) and 
    (select sum(quantity) from fmtables..[orders] ox  
    inner join fmtables..[orderlines] olx on ox.order_id = olx.order_id 
    where [product_code] in(select [product_code] from fmtables..[products] 
    where [category_code] in('1','2','3','4'))) >= @countOfUnitsBought 
) 
select * from res; 

你正在運行sql-server 2008嗎?有一個bug也可以解釋您的性能問題。

+0

感謝您回答t-cluasen。我解決了它。 – scottsanpedro 2015-03-03 15:18:00

+0

@scottsanpedro你解決了嗎,還是我的解決方案解決了它?如果這是解決方案,請接受答案。我相信我已經修復了你的代碼中的一些錯誤 – 2015-03-03 15:21:17

+0

我沒有你的答案解決了它,但我確信你的答案是一樣的。 – scottsanpedro 2015-03-03 15:27:33