2012-06-08 2 views
2

Я пытаюсь вызвать хранимые процедуры с использованием 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 
+0

Возможно, вы захотите оптимизировать хранимые процессы http://msdn.microsoft.com/en-us/library/ms187735(v=sql.105).aspx - SET SHOWPLAN_ALL и дБ, запустив sql-профилировщик отслеживать и помещать это через Мастер настройки производительности и применять рекомендации индексов и статов. –

ответ

7

Я полагаю, вы используете ADO.NET SqlCommand?

SqlCommand.CommandTimeout будет установить тайм-аут вам требуется

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

Хранимая процедура прекращается, как только клиент времени ожидания.

+0

Если SQL Server отмечает, что клиент отказался от соединения, хранимая процедура будет остановлена. Он не будет продолжать работать. – Andomar

+1

@Andomar У меня есть опыт, который sprocs просто продолжает исполнять. Меня когда-то интересовал и этот вопрос. Можете ли вы показать мне настройку, когда сервер перестает выполняться после истечения времени клика? – buckley

+0

Напишите sproc, который никогда не заканчивается, например 'while 1 = 1 begin insert YourTable values ​​(1) end'. Дайте ему время ожидания от C#. – Andomar

9

Четыре минуты становятся довольно массивными, даже база данных с миллионами строк и множеством столов для объединения могут возвращать результаты в считанные секунды, если они спроектированы и запрошены правильно.

Вам нужно провести некоторое время с помощью sproc и Explain Plan, чтобы выяснить, почему это так долго. Рассмотрим сегментацию данных, разбивку запроса на отдельные фрагменты, индексы, построение соединений, подзапросы и т. Д. Объяснение плана даст вам то, где оно напрасно тратит свое время.

Сохраненные процедуры не должны занимать четыре минуты, особенно если они работают на каком-то клиентском приложении.

У меня был унаследованный запрос, который занимал 52 минуты для запуска, с небольшим рефактором это было 40 секунд, затем через немного больше, 6 секунд. Даже 40 секунд толкает его на самом деле.

Если у вас есть такой массивный запрос и он основан на отчетности, рассмотрите хранилище данных, так как оно будет содержать схему, гораздо более подходящую для этих целей.

+0

+1: Это хороший ответ ИМО. Проведите некоторое исследование и попытайтесь проанализировать, где узкое место. Не просто применять бандаж, устанавливая тайм-аут на несколько световых лет. –

+0

Но вопрос был не в том, можно ли сделать запрос быстрее. Возможно, OP даже не разрешено изменять SP. – Andomar

+1

@ Прибыль от прибыли от Andomar может быть получена путем изменения индексов на таблицах между прочим. Это не должно быть изменением для SP. –

3

Вы можете использовать Asynchronous Procedure Execution. Это надежный способ: способ выполнить процедуру без необходимости ждать клиента.

Но процедура, подобная той, которую вы описываете (которая должна периодически запускаться и сканировать почту), скорее всего является . Задача и SQL Agent лучше подходит.

0

В соответствии с вашим примером кода вы используете «Объявить» для каждой переменной. Почему вы не используете единую декларацию для каждой переменной.Как это

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» вместо «установить» для каждой переменной, как этот

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 
) 

и вы использовали «с (NOLOCK)» при вставке в #table, так что вы должны использовать с (NOLOCK), когда выбрать из # T способный тоже. И если ваш #table используется только один раз для вставки, то я предлагаю вам использовать с помощью CTE (Common Table Expression) то же самое, это может увеличить производительность вашего SP.

Смежные вопросы