0

在开发的代码中面临超时过期问题。下面分享的是发生超时的存储过程。代码的目的:从前端传递的日期(使用 Windows 应用程序 vb.net 代码中的 forloop)用于 100 万个案例,需要根据收到的日期计算日期差异。

create procedure sp_getdatediff

@strd1 date = null,
@strd2 date = null,
@strd3 date = null,
@strd4 date = null,
@strd5 date = null,
@strd6 date = null,
@strd7 date = null,
@strd8 date = null,
@strd9 date = null,
@strd10 date = null,
@strd11 date = null
as
begin

declare @vardatediff1 int
declare @vardatediff2 int
declare @vardatediff3 int
declare @vardatediff4 int
declare @vardatediff5 int

set @vardatediff1 = [fn_getdiff](@strd1,@strd2,@strd3) ----- input parameters are dates passed from frontend
set @vardatediff2 = [fn_getdiff](@strd2,@strd4,@strd5)
set @vardatediff3 = [fn_getdiff](@strd4,@strd5,@strd6)
set @vardatediff4 = [fn_getdiff](@strd5,@strd7,@strd8)
set @vardatediff5 = [fn_getdiff](@strd9,@strd10,@strd11)

update tbl_Scheduler set col_dif1 = @vardatediff1 , col_dif2 = @vardatediff2 , 
col_dif3 = @vardatediff3 , col_dif4 = @vardatediff4 , col_dif5 = @vardatediff5
where id = @id

end

功能代码:

create function [fn_getdiff]
(
@startdate date = null,
@enddate date = null,
@ccode varchar(10) = null
)
returns integer


as
begin
declare @count integer 
declare @tdaycount integer 
if (@startdate is null or @startdate = '')
begin
    set @count = 0
end
else if (@enddate is null or @enddate = '')
begin
    set @count = 0
end
else
begin

    select @tdaycount = count(distinct(convert(date,tdays))) from tbl_holidays with (nolock) where (convert(date,tdays,105) >= convert(date,@startdate,105))
    and (convert(date,tdays,105) <= convert(date,@enddate,105)) and tcode in (select id from tbl_code with (nolock) where id = @ccode)

    select @count  = datediff(@startdate,@enddate)
    
    set @count = @count - @tdaycount 
    
end
return @count 

end

此代码中是否需要优化以消除超时问题?怎么能做同样的事情?

4

2 回答 2

0

在您的函数中使用 IN 可以用 JOIN 代替。

您的查询 :

SELECT @tdaycount = COUNT(DISTINCT(CONVERT(DATE, tdays)))
FROM   tbl_holidays WITH(NOLOCK)
WHERE  (CONVERT(DATE, tdays, 105) >= CONVERT(DATE, @startdate, 105))
        AND (CONVERT(DATE, tdays, 105) <= CONVERT(DATE, @enddate, 105))
        AND tcode IN (SELECT id
                      FROM tbl_code WITH(NOLOCK)
                      WHERE id = @ccode);

重写:

SELECT @tdaycount = COUNT(DISTINCT(CONVERT(DATE, tdays)))
FROM   tbl_holidays  AS h
       JOIN tbl_code  AS c
          ON h.tcode = c.id
WHERE    (CONVERT(DATE, tdays, 105) >= CONVERT(DATE, @startdate, 105))
          AND (CONVERT(DATE, tdays, 105) <= CONVERT(DATE, @enddate, 105))
          AND  c.id = @ccode;

当 A = B 且 B = C 时 A = C,所以:

...
              ON h.tcode = c.id
    WHERE    ...
              AND  c.id = @ccode;

重写(2):

SELECT @tdaycount = COUNT(DISTINCT(CONVERT(DATE, tdays)))
FROM   tbl_holidays  AS h
WHERE    (CONVERT(DATE, tdays, 105) >= CONVERT(DATE, @startdate, 105))
          AND (CONVERT(DATE, tdays, 105) <= CONVERT(DATE, @enddate, 105))
          AND  tbl.tcode = @ccode;

你不尊重发帖规则......所以我们不能帮助你这么多。请把你的表和索引的描述作为 DDL SQL 语句。可能CONVERTs没用...

于 2021-09-14T15:58:30.953 回答
0

您的函数包含这段 SQL。

select @tdaycount = count(distinct(convert(date,tdays))) 
 from tbl_holidays with (nolock) 
where (convert(date,tdays,105) >= convert(date,@startdate,105))
and (convert(date,tdays,105) <= convert(date,@enddate,105)) 
and tcode in (select id from tbl_code with (nolock) where id = @ccode)

日期转换错误

CONVERT(DATE, @enddate, 105)产生日期的形式31-12-2006<=我怀疑在这种格式上使用比较是没有意义的,因为30-12-2007会出现在31-12-2006. 您的数据已经采用DATE格式,因此您可以在不转换的情况下进行比较。

Sargability 性能反模式

它包含几个这样的性能反模式:

WHERE function(column) >= function(constant)

这是一个反模式,因为它是一个不可分割的过滤器。你想要的是这种模式

WHERE column >= constant

或者

WHERE column >= function(constant)

结合表格上的适当索引。

指数

tbl_holidays您的表上的多列索引(tcode, tdays)将允许服务器通过范围扫描该索引来满足您的查询。尝试这个。

CREATE INDEX tcode_tdays ON tbl_holidays (tcode, tdays); 

改写

SELECT @tdaycount = COUNT(DISTINCT tdays) 
  FROM tbl_holidays WITH (NOLOCK)
 WHERE tdays >= @startdate
   AND tdays <= @enddate
   AND tcode in (SELECT id 
                   FROM tbl_code WITH (NOLOCK) 
                  WHERE id = @ccode)

我不知道这会节省多少时间。但它会节省一些。

默认超时时间太短

.NET 的 SQL 类设置为 30 秒超时。如果您正在处理数百万行(数以十万计)不够长的行。尝试将超时设置为十分钟或任何有意义的持续时间。

Dim command = conn.CreateCommand()
...
command.CommandTimeout = 600  ' ten minutes 
于 2021-09-15T11:33:09.467 回答