等待接收结果偏移/延迟 1 个结果
本文关键字:结果 延迟 等待 | 更新日期: 2023-09-27 18:31:12
我正在使用SQL Service Broker。 一个连接在队列中发送带有 XML 消息的消息。 我有一个独立的连接,WAITFOR (RECEIVE TOP (1) ...), TIMEOUT 5000
. 这在单个管理工作室查询或单个 ADO.NET SQL 命令执行中使用循环读取器进行WHILE (1=1)
循环。下一个结果()。
所有这些似乎都已正确配置,因为我最终得到了我期望的每个结果。
但问题是,最近的结果总是被阻止!
假设它一直在运行并且没有SEND
,所以它只是每 5 秒将"None"打印到控制台上超时。
现在我从SQL Management Studio查询中SEND
。 SEND
命令将立即成功完成。 在正常的超时间隔之前,我立即在控制台中得到"无"。 然后在下一个超时间隔,我的"更新"事件出现!
如果我在运行"无"后SEND
两条消息,那么我将立即得到"无",然后是一条"更新"。 同样,在下一个超时间隔,将出现第二个"更新"。
我可以SEND
十条消息,并立即得到"无"和九条"更新"。 然后我等待五秒钟超时并获得最终的"更新"。
所有SEND
都在同一个对话中,我永远不会结束对话。 我不保留。
如果我在 RECEIVE 循环运行时对队列进行脏读,则队列始终为空。 如果我停止接收循环,它就会填满。 如果我从另一个管理工作室查询窗口接收,另一个线索是当我停止查询时,最终输出始终出现。 这两个事实让我认为队列立即被取消排队,但读者端有一些东西被锁定(但是什么??
起初,我认为这只是管理工作室的一种奇怪行为,我以前见过PRINT
(?)有时会延迟。 但我不希望同样的行为出现在 ADO.NET
也许它与 SSB 无关,只是 WAITFOR 或只是多个结果集的流式传输。 我将调查这些选项,但我希望在此期间有人可能会认识到这一点。
您熟悉这些症状吗?
谢谢!
- 有没有办法允许在下一个阻止操作之前将结果刷新到连接? 结果/结果集交付是否会延迟?
- 我没有看到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
我相信RAISERROR(...用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
- https://stackoverflow.com/a/13047982/122718
- http://msdn.microsoft.com/en-us/library/ms178592.aspx
另一方面,代码中的所有副作用(写入表或其他 DML)都会立即发生。只有客户端应用接收延迟PRINT
消息。此延迟根本不应该影响您的生产应用程序,因为所有有用的副作用都会立即发生。
简而言之,要么忽略问题,要么使用 RAISERROR('Message', 0, 0) WITH NOWAIT
.仅当严重性大于 10 时,才会引发异常。