3

我正在尝试使用 C# 调用存储过程。存储过程的运行时间很长(3 到 4 分钟),当我尝试运行它们时它们会导致超时异常。我怎样才能让他们在更长的超时时间内完成运行?

而当它抛出异常时,存储过程是继续在服务器上运行,还是停止?

我的应用程序是一个游戏服务器,存储过程运行以更新和删除邮件。它运行缓慢,因为有太多的记录和太多的连接,用户无法在 SP 运行的同时插入另一条记录。

我只需要运行SP并等待服务器响应很长时间。

@minitech 感谢您编辑我的问题

这是SP代码

ALTER    PROCEDURE [dbo].[SP_Mail_Scan]
 @NoticeUserID nvarchar(4000) output

AS  
Set @NoticeUserID=''
Declare @AuctionID Int        
Declare @AuctioneerID Int
Declare @AuctioneerName Nvarchar(100)
Declare @BuyerID Int
Declare @BuyerName Nvarchar(100)
Declare @ItemID Int
Declare @PayType Int
Declare @Price Int
Declare @Name Nvarchar(200)


Declare @MailID Int
Declare @SenderID Int
Declare @Sender Nvarchar(100)
Declare @ReceiverID Int
Declare @Receiver Nvarchar(100)
Declare @Title Nvarchar(1000)
Declare @Content Nvarchar(4000)
Declare @SendTime DateTime
Declare @IsRead Bit
Declare @IsDelR Bit
Declare @IfDelS Bit
Declare @IsDelete Bit
Declare @Annex1 Nvarchar(100)
Declare @Annex2 Nvarchar(100)
Declare @Gold Int
Declare @Money Int
Declare @Remark Nvarchar(200)
Declare @Annex3 Nvarchar(100)
Declare @Annex4 Nvarchar(100)
Declare @Annex5 Nvarchar(100)


Set @SenderID =0
Set @Sender =dbo.GetTranslation('SP_Mail_Scan.Sender')  --
Set @ReceiverID = ''
Set @Receiver = ''
Set @Title =dbo.GetTranslation('SP_Mail_Scan.Title')
Set @Content =dbo.GetTranslation('SP_Mail_Scan.Content')
Set @SendTime  = getdate()
Set @IsRead  = 0
Set @IsDelR = 0
Set @IfDelS = 0
Set @IsDelete =0
Set @Annex1 =''
Set @Annex2 =''
Set @Gold =0
Set @Money =0
Set @Annex3 =''
Set @Annex4 =''
Set @Annex5 =''

If object_id('tempdb..#PayMail') Is Not null
Drop Table #PayMail 

Create Table #PayMail 
(
id Int Identity(1,1), 
MailID Int Not Null,
SenderID Int Not Null,
Sender Nvarchar(200) Not null,
ReceiverID Int not null,
Receiver Nvarchar(200) not null,
Title Nvarchar(1000) not null,
Annex1 Nvarchar(100) not null,
Annex2 Nvarchar(100) not null,
Annex3 Nvarchar(100) not null,
Annex4 Nvarchar(100) not null,
Annex5 Nvarchar(100) not null,
) 

insert into #PayMail select [ID],SenderID,Sender,ReceiverID,Receiver,Title,isnull(Annex1,''),isnull(Annex2,''),isnull(Annex3,''),isnull(Annex4,''),isnull(Annex5,'') from User_Messages with(nolock) 
where IsExist=1 and Type>100 and datediff(hh,SendTime,getdate())>ValidDate and [Money]>0

  declare @NewTitle nvarchar(200)
  declare @NewContent nvarchar(200)
  set @NewTitle = dbo.GetTranslation('SP_Mail_Scan.Msg1')
  set @NewContent =dbo.GetTranslation('SP_Mail_Scan.Msg2')

set xact_abort on 
  begin tran

INSERT INTO User_Messages( SenderID, Sender, ReceiverID, Receiver, Title, Content, SendTime, IsRead, IsDelR, IfDelS, IsDelete, Annex1, Annex2, Gold, Money, IsExist,Type,Remark, Annex3, Annex4, Annex5) 
      select ReceiverID,Receiver,SenderID,Sender,@NewTitle+Title,REPLACE(@NewContent,'{0}',Receiver),getdate(), 0, 0, 0, 0,Annex1,Annex2,0,0,1,7,'Gold:0,Money:0,Annex1:'+Annex1+',Annex2:'+Annex2+',Annex3:'+Annex3+',Annex4:'+Annex4+',Annex5:'+Annex5,Annex3,Annex4,Annex5
    from #PayMail

  if @@error<>0 or @@ROWCOUNT =0
    begin
      rollback tran
      return 1 
   end

  update User_Messages set IsExist=0,@NoticeUserID = @NoticeUserID + cast(SenderID as nvarchar(50)) + ',' from User_Messages where [ID] in (select MailID from #PayMail)

  if @@error<>0 or @@ROWCOUNT =0
    begin
      rollback tran
      return 1 
   end

  commit tran
set xact_abort off

if len(@NoticeUserID)>0
begin
 set @NoticeUserID = substring(@NoticeUserID,1,len(@NoticeUserID)-1)
end
--set @NoticeUserID='100,200'

return 0
4

4 回答 4

9

四分钟已经变得相当长了,如果以正确的方式设计和查询,即使是具有数百万行和大量要连接的表的数据库也可以在几秒钟内返回结果。

您需要花一些时间处理 sproc 和 Explain Plan 来弄清楚为什么它需要这么长时间。考虑数据分割,将查询拆分为离散的块、索引、连接的构建方式、子选择等。解释计划将告诉你它在哪里浪费时间。

存储过程不应该花费四分钟的时间来运行,尤其是当它们在某种客户端应用程序上运行时。

我有一个遗留查询需要 52 分钟才能运行,通过一个小的重构它是 40 秒,然后再过一点,6 秒。甚至 40 秒都在推动它。

如果您有如此庞大的查询并且它是基于报告的,请考虑使用数据仓库,因为它将具有更适合这些目的的模式设计。

于 2012-06-09T00:02:42.697 回答
8

我想你正在使用 ADO.NET SqlCommand?

SqlCommand.CommandTimeout 将设置您需要的超时

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout(v=vs.80).aspx

一旦客户端超时,存储过程就会停止。

于 2012-06-09T00:01:37.523 回答
3

您可以使用异步过程执行。这是一种可靠的方式来执行该过程,而客户端不必等待它完成。

但是像您描述的过程(必须定期运行并扫描邮件)更有可能是一项工作,而SQL 代理更适合。

于 2012-06-09T06:02:44.453 回答
-1

根据您的示例代码,您对每个变量都使用了“声明”。为什么不对每个变量使用单个 Declare。像这样

Declare  @AuctionID Int        
        ,@AuctioneerID Int
        ,@AuctioneerName Nvarchar(100)
        ,@BuyerID Int
        ,@BuyerName Nvarchar(100)
        ,@ItemID Int
        ,@PayType Int
        ,@Price Int
        ,@Name Nvarchar(200)

        ,@MailID Int
        ,@SenderID Int
        ,@Sender Nvarchar(100)
        ,@ReceiverID Int
        ,@Receiver Nvarchar(100)
        ,@Title Nvarchar(1000)
        ,@Content Nvarchar(4000)
        ,@SendTime DateTime
        ,@IsRead Bit
        ,@IsDelR Bit
        ,@IfDelS Bit
        ,@IsDelete Bit
        ,@Annex1 Nvarchar(100)
        ,@Annex2 Nvarchar(100)
        ,@Gold Int
        ,@Money Int
        ,@Remark Nvarchar(200)
        ,@Annex3 Nvarchar(100)
        ,@Annex4 Nvarchar(100)
        ,@Annex5 Nvarchar(100)

甚至你为什么不为每个变量使用单个“选择”而不是“设置”

Select   @SenderID =0
        ,@Sender = dbo.GetTranslation('SP_Mail_Scan.Sender')  --
        ,@ReceiverID = ''
        ,@Receiver = ''
        ,@Title = dbo.GetTranslation('SP_Mail_Scan.Title')
        ,@Content = dbo.GetTranslation('SP_Mail_Scan.Content')
        ,@SendTime  = getdate()
        ,@IsRead  = 0
        ,@IsDelR = 0
        ,@IfDelS = 0
        ,@IsDelete =0
        ,@Annex1 =''
        ,@Annex2 =''
        ,@Gold =0
        ,@Money =0
        ,@Annex3 =''
        ,@Annex4 =''
        ,@Annex5 =''

您已经为插入操作创建了#table,但您没有为该表指定任何键,我建议您应该定义主键

Create Table #PayMail 
(
     id Int Identity(1,1) Primary Key
    ,MailID Int Not Null
    ,SenderID Int Not Null
    ,Sender Nvarchar(200) Not null
    ,ReceiverID Int not null
    ,Receiver Nvarchar(200) not null
    ,Title Nvarchar(1000) not null
    ,Annex1 Nvarchar(100) not null
    ,Annex2 Nvarchar(100) not null
    ,Annex3 Nvarchar(100) not null
    ,Annex4 Nvarchar(100) not null
    ,Annex5 Nvarchar(100) not null
)

并且您在插入#table 时使用了“with (Nolock)”,因此在从#table 中选择时也应该使用 with (Nolock)。如果您的#table 仅用于插入一次,那么我建议您应该使用 With CTE(通用表表达式),它可能会提高您的 SP 性能。

于 2015-06-17T05:08:20.867 回答