以较长的运行时间调用存储过程

时间:2012-06-08 23:53:36

标签: c# sql-server stored-procedures

我正在尝试使用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 个答案:

答案 0 :(得分:9)

四分钟变得非常沉重,即使是一个拥有数百万行和大量表格的数据库,如果以正确的方式设计和查询,也可以在几秒钟内返回结果。

你需要花一些时间处理sproc和解释计划,找出为什么这么长时间。考虑数据分段,将查询拆分为离散的块,索引,如何构建连接,子选择等。解释计划将为您提供浪费时间的地方。

存储过程不应该花费四分钟才能运行,特别是如果它们在某种客户端应用程序上运行。

我有一个遗留查询,需要52分钟才能运行,一个小的重构是40秒,然后再多一点,6秒。即使是40秒也是如此。

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

答案 1 :(得分:7)

我认为您正在使用ADO.NET SqlCommand?

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

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

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

答案 2 :(得分:3)

您可以使用Asynchronous Procedure Execution。这是一种可靠的方式来执行客户端必须等待它完成的过程。

但是像您描述的那样(必须定期运行并扫描邮件)的过程更可能是作业,而SQL Agent更适合。

答案 3 :(得分:0)

根据您的示例代码,您已使用&#34;声明&#34;对于每个变量。为什么不为每个变量使用单个Declare。喜欢这个

clickSound = new SoundFile(PApplet, "bike-passing-by.wav");

即使为什么不使用单曲&#39;选择&#39;而不是&#34;设置&#34;对于像这样的每个变量

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)

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

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 =''

你已经和#34;一起使用了(Nolock)&#34;当插入#table时,所以你也应该在选择#table时使用(Nolock)。如果您的#table仅用于插入一次,那么我建议你应该使用CTE(公用表表达式),这可能会提高你的SP性能。