2013-03-27 111 views
1

我有目的的查詢來查找表item_location記錄,並在表operation_detail不存在了一年中的特定月份查詢超時使用NOT EXIST

SELECT il.item_id, 
     il.SEQUENCE, 
     SUM (il.quantity) AS quantity, 
     i.buy_price, 
     i.sell_price, i.item_name, i.unit_measure_id, 
     i.is_raw_item AS is_raw 
FROM item_location il, item i 
WHERE il.quantity <> 0 
AND il.item_id = i.item_id 
AND il.SEQUENCE = i.SEQUENCE 
AND NOT EXISTS (
       SELECT od.* 
       FROM operation_detail od, operation_header oh, rt_operation o 
       WHERE od.item_id = il.item_id 
       AND od.SEQUENCE = il.SEQUENCE 
       AND od.operation_header_id = oh.operation_header_id 
       AND oh.operation_type_id = o.operation_type_id 
       AND o.operation_stock IN ('I', 'O') 
       AND MONTH (oh.operation_date) = @MONTH 
       AND YEAR (oh.operation_date) = @YEAR) 
GROUP BY il.item_id, 
     il.SEQUENCE, 
     i.buy_price, 
     i.sell_price, 
     i.item_name, 
     i.unit_measure_id, 
     i.is_raw_item 

注意,從.net平臺上運行此查詢使用DataAdapter給超時,從SQL運行它帶到40年代

我主要是概率超時....任何建議

+2

對operation_detail,operation_header和rt_operation任何索引? – hkutluay 2013-03-27 07:25:17

+3

曾經看過執行計劃嗎? – 2013-03-27 07:27:08

+0

你正在使用什麼數據庫系統? – 2013-03-27 08:28:00

回答

0

爲提高性能,請勿使用非SARGable where子句。你的主要錯誤是使得查詢不是SARGable,而是直接在WHERE子句中的列上執行函數。這不會使用索引。

看看下面這個例子,其中申報查詢新的參數強制索引查找操作

DECLARE @YEAR int = 1971, 
     @MONTH int = 11, 
     @StartDate datetime, 
     @EndDate datetime 
SELECT @StartDate = CAST(CAST(@YEAR AS nvarchar(4)) + RIGHT('0' + CAST(@MONTH AS nvarchar(2)), 2) + '01' AS datetime), 
     @EndDate = DATEADD(month, 1, CAST(@YEAR AS nvarchar(4)) + RIGHT('0' + CAST(@MONTH AS nvarchar(2)), 2) + '01') 

SELECT 
... 
WHERE od.item_id = il.item_id 
    AND od.SEQUENCE = il.SEQUENCE 
    AND od.operation_header_id = oh.operation_header_id 
    AND oh.operation_type_id = o.operation_type_id 
    AND o.operation_stock IN ('I', 'O') 
    AND oh.operation_date >= @StartDate AND oh.operation_date < @EndDate 
+0

夥計們正在使用SQL 2008,我的主要問題是我不明白爲什麼這樣的查詢需要很長時間才能執行,現在給出month = 2執行時間是1:30 mn – user2214544 2013-03-27 10:39:18

+0

您是否在operation_date列上有索引? – 2013-03-27 10:58:40

+0

thx亞歷山大......這是解決方案 – user2214544 2013-03-27 11:53:37

2

默認的超時運行查詢爲30秒,如果你的命令需要時間越長,它將被終止。我想你應該優化您的查詢運行速度更快,但你也可以增加超時爲您的數據適配器:

dataAdapter.SelectCommand.CommandTimeout = 120; // Two minutes 
+0

- ,'ConnectionTimeout'不是要設置的屬性,而是特定命令的'CommandTimeout' ... – 2013-03-27 07:27:38

+0

@Andreas對不起。謝謝你糾正我。 – 2013-03-27 07:29:15

+0

另外,我寧願寫''TimeSpan.FromMinutes(2).TotalSeconds';)但這只是一個品味問題... – 2013-03-27 07:30:04

0

每當我看到查詢比幾個分組列多了,我開始想查詢可以重寫。一般來說,您應該嘗試僅對鍵列進行分組,將鍵和聚合結果存儲在臨時表中,然後加入該臨時表以獲取更多詳細信息。例如:

insert into 
    #tmp 
select 
    key1, key2, sum(things) 
from 
    table; 

然後:

select 
    table.key1, table.key2, 
    tmp.sum_of_all_things, 
    table.other_stuff, table.extra_data 
from 
    #tmp tmp 
    join 
    table on tmp.key1 = table.key1 and tmp.key2 = table.key2 

這將避免將所有非鍵列進行排序(這是爲group by操作的一部分發生了什麼)的所有開銷。

其次,因爲你必須在not exists子句中相關子查詢,則應該提供關於匹配謂詞的索引或索引(在這種情況下,item_idsequence)。 exists的工作方式是,如果結果集包含任何行,則返回true,,但仍需要爲外部查詢的每一行重新執行內部查詢。所以你需要索引來減少這種折磨。

由於您的內部查詢本身包含3個連接,因此我會認真考慮分別運行它並將結果存儲在另一個臨時表中。

+0

如何提供索引? – user2214544 2013-03-27 08:19:19

+0

您的意思是創建它們,還是查看錶格上的現有索引或其他內容? – 2013-03-27 08:26:31

+0

我的意思是你希望我這樣做,你建議提供索引,那麼我該如何提供它們? – user2214544 2013-03-27 10:00:22