2

我有一个查询,目的是查找表 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

请注意,使用给定超时从.net平台运行此查询,从 SQL 运行它需要 40 秒DataAdapter

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

4

3 回答 3

2

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

dataAdapter.SelectCommand.CommandTimeout = 120; // Two minutes
于 2013-03-27T07:26:42.167 回答
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操作的一部分发生的)。

其次,由于您在子句中有一个相关的子查询,您应该在匹配谓词(在本例中为and )not exists上提供一个或多个索引。该方法有效,如果结果集包含任何行,它将返回 true,但仍需要为外部查询的每一行重新执行内部查询。所以你需要索引来减少这种痛苦。item_idsequenceexists

由于您的内部查询本身包含 3 个连接,因此我会认真考虑单独运行它并将结果存储在另一个临时表中。

于 2013-03-27T07:41:03.123 回答
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 
于 2013-03-27T10:03:52.623 回答