WAITFOR RECEIVE результаты смещены / задержаны на 1 результат
Я использую SQL Service Broker. Одно соединение ОТПРАВЛЯЕТ сообщение в очередь с сообщением XML. У меня есть независимая связь, которая WAITFOR (RECEIVE TOP (1) ...), TIMEOUT 5000
, Это идет в WHILE (1=1)
Цикл в одном запросе Management Studio или выполнении одной команды SQL ADO.NET с зацикленным читателем.NextResult().
Все это, кажется, правильно настроено, поскольку я в конечном итоге получаю каждый ожидаемый результат.
Но проблема в том, что самый последний результат всегда сдерживается!
Допустим, он работает и не было SEND
s, так что время ожидания остается равным "None", выводимому на консоль каждые 5 секунд.
Ну теперь я SEND
из запроса SQL Management Studio. SEND
Команда завершается успешно и сразу. Я немедленно получаю "None" в консоли до обычного интервала ожидания. Затем в следующий интервал времени появляется мое событие "Обновление"!
И если я SEND
два сообщения после запуска "None", затем я немедленно получу "None" и затем одно "Update". Снова, в следующий интервал времени ожидания, появится второе "Обновление".
Я могу SEND
десять сообщений и сразу же получите "Нет" и девять "Обновлений". Затем я жду пятисекундный таймаут и получаю последнее "обновление".
Все SEND
они в одном разговоре, и я никогда не заканчиваю разговор. Я не СОХРАНЯЮ.
Если я выполняю грязное чтение очереди во время выполнения цикла RECEIVE, очередь всегда пуста. Если я остановлю цикл приема, он заполняется. Если я получаю из другого окна запроса Management Studio, дополнительная подсказка в том, что когда я останавливаю запрос, всегда появляется окончательный результат. Эти два факта заставляют меня думать, что очередь сразу же снимается с очереди, но что-то защелкивается на стороне читателя (но что??).
Сначала я подумал, что это просто странное поведение Management Studio, которое я видел раньше, где PRINT
(?) иногда задерживается. Но я не ожидал бы, что такое же поведение проявится в ADO.NET
Возможно, это не имеет ничего общего с SSB, просто WAITFOR или просто потоковой передачей нескольких ResultSets. Я изучу эти варианты, но я надеюсь, что кто-то может распознать это в то же время.
Вам знакомы эти симптомы?
Спасибо!
- Есть ли способ разрешить сброс результатов в соединение перед следующим действием блокировки? Доставка результатов / результатов отложена?
- Я не вижу никакой дополнительной блокировки в результатах sp_lock сразу после
SEND
(ни как иначе)
Для @Rikalous, вот ADO.NET
using (var cmd = connection.CreateCommand())
{
cmd.CommandTimeout = 0;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "upWaitForReceive";
using (var reader = cmd.ExecuteReader())
{
do
{
while (reader.Read()) // Individual messages received
{
string eventType = reader["EventType"] as string;
// do something with the message
}
} while (reader.NextResult()); // next batch
}
}
Цикл sql:
SELECT 'Initialized' AS EventType
WHILE (1=1) BEGIN
;DECLARE
@ConversationHandle UNIQUEIDENTIFIER,
@MessageTypeName SYSNAME,
@MessageBody XML
;WAITFOR(
RECEIVE TOP (1) @ConversationHandle = conversation_handle, @MessageTypeName = message_type_name, @MessageBody = message_body
FROM [dbo].[{0}_EventsQueue]
), TIMEOUT 5000
IF (@@ROWCOUNT = 0) BEGIN
SELECT 'None' AS EventType; -- Allow the blocking call to spin anyway
CONTINUE;
END
IF (@MessageTypeName = ...) BEGIN
SELECT ...
END ELSE IF (@MessageTypeName = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog') BEGIN
END CONVERSATION @ConversationHandle
SELECT @Message = 'Conversation Terminated' -- Not Expected
RAISERROR (@Message, 11, 1)
RETURN
END
END
;END CONVERSATION @ConversationHandle -- This will never be reached. But if it were, this is what should be done
2 ответа
Я считаю, что RAISERROR (...) WITH NOWAIT должны очистить буфер, но я не играл с ним в течение достаточно долгого времени.
Печатные сообщения отправляются не сразу. Я регулярно вижу произвольно высокие задержки печатных отладочных сообщений. Я думаю, что SQL Server ожидает заполнения сетевого пакета или какой-либо другой буферизации.
Если вы просто запустите бесконечный цикл, который печатает небольшое сообщение каждую секунду, вы можете получить первые N сообщений через N секунд, все сразу. Это может быть только в случае с TCP. Может быть, общая память быстрее, я не знаю.
Я никогда не видел, чтобы наборы результатов были отложены. Так что попробуйте "печать", выполнив SELECT 'msg'
,
Проблема отложенных записей клиенту хорошо известна:
- http://connect.microsoft.com/SQLServer/feedback/details/124994/print-output-lags-in-stored-procedure-it-is-always-delay-during-execution-of-a-batch-or-a-stored-procedure
- /questions/40656690/sql-server-zaderzhka-pered-vyivodom-operatorom-pechati/40656704#40656704
- http://msdn.microsoft.com/en-us/library/ms178592.aspx
С другой стороны, все побочные эффекты в вашем коде (запись в таблицу или другой DML) происходят в любом случае немедленно. Только клиентское приложение получает PRINT
сообщения задерживаются. Эта задержка не должна влиять на ваше производственное приложение, потому что все полезные побочные эффекты происходят немедленно.
Короче, либо игнорируй проблему, либо используй RAISERROR('Message', 0, 0) WITH NOWAIT
, Исключение будет выдано только в том случае, если серьезность больше 10.