等待接收结果偏移/延迟 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查询中SENDSEND命令将立即成功完成。 在正常的超时间隔之前,我立即控制台中得到"无"。 然后在下一个超时间隔,我的"更新"事件出现!

如果我在运行"无"后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

等待接收结果偏移/延迟 1 个结果

我相信RAISERROR(...用NOWAIT应该刷新缓冲区,但我有一段时间没有玩它了。

打印消息不会立即发送。我经常看到打印的调试消息的任意高延迟。我认为SQL Server等待网络数据包已满或某种其他类型的缓冲。

如果您只是运行一个每秒打印一条小消息的无限循环,您可能会在 N 秒后立即收到前 N 条消息。这可能只在 TCP 上出现。也许共享内存更快,我不知道。

不过,我从未见过结果集延迟。因此,请尝试通过执行SELECT 'msg'来"打印"。

延迟写入客户端的问题似乎是众所周知的:

  1. 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
  2. https://stackoverflow.com/a/13047982/122718
  3. http://msdn.microsoft.com/en-us/library/ms178592.aspx

另一方面,代码中的所有副作用(写入表或其他 DML)都会立即发生。只有客户端应用接收延迟PRINT消息。此延迟根本不应该影响您的生产应用程序,因为所有有用的副作用都会立即发生。

简而言之,要么忽略问题,要么使用 RAISERROR('Message', 0, 0) WITH NOWAIT .仅当严重性大于 10 时,才会引发异常。