2013-03-27 80 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