使用NOT EXIST查询超时

时间:2013-03-27 07:21:59

标签: c# sql

我有一个查询目的是查找表item_location中的记录,并且在一年中的特定月份不存在于表operation_detail中

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

请注意,使用.netDataAdapter平台运行此查询会产生超时,从SQL运行它需要40秒

我的主要问题是TimeOut ....任何建议

3 个答案:

答案 0 :(得分:2)

运行查询的默认超时为30秒,如果命令需要更长时间,则会终止。我想你应该优化你的查询以更快地运行,但你也可以增加数据适配器的超时时间:

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

答案 1 :(得分: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个连接,我会认真考虑单独运行它并将结果存储在另一个临时表中。

答案 2 :(得分:0)

为了提高性能,请不要使用非SARGable where子句。你的主要错误是什么使查询非SARGable直接在WHERE子句的列上的函数。这不会使用索引。

查看此示例,其中声明查询强制INDEX SEEK操作的新参数

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