이벤트 알림에 문제가 있습니다. 메시지가 수신되는 시스템 / 드라이브 / 데이터베이스 (수신자)에서 아무도보고 있지 않을 때 드라이브가 가득 차서 하루 종일 백업되었습니다.
이제 드라이브의 공간을 확보 했으므로 대기열에 메시지를 수락하지만 처리하지 않는 것 같습니다. 대기열에 현재 2 천 2 백만 개의 메시지가 있고 커지는 경우에도 새로운 레코드가 삽입되지 않습니다. 대기열이 활성화되었습니다.
is_activation_enabled = 1
is_receive_enabled = 1
is_enqueue_enabled = 1
에 활성화 된 SP가 표시 activation_procedure
되지만에서 살펴보면 SP_WHOISACTIVE
활성화 된 독자가 표시되지 않습니다.
드라이브를 다시 터뜨리기 전에 내가 뭘 잘못하고 있니? 메시지를 처리하거나 플러시하려면 어떻게해야합니까? 미리 감사드립니다.
최신 정보
한 가지 생각-내가 가지고 있기 때문에 is_enqueue_enabled
모든 메시지를 처리 할 수있을 때까지 모든 메시지를 저장하고 있습니까? 그렇다면 안전하게 끌 수 있습니까?
CREATE PROCEDURE [dbo].[Parse_EN_Messages]
AS
--mdb 2012/09/05 version 1.2
-- With apologies and thanks to Remus Rusanu, Jonathon Kehayias, Mladen Prajdic, and Jasper Smith for writing
-- about EN, answering questions, and getting the word out about this awesome feature of SQL Server 2005+.
-- Also thanks to Mikael Eriksson for a faster parse with the XML filter.
-- Their code modified, combined, and used below. Any errors herein are mine, not theirs.
-- Part of the code came from MVP Deep Dives Vol 1 Chapter 28 (Mladen), PASS Presentations by Jasper and Jonathon,
-- and Stackexchange (below) from Remus and Mikael Eriksson
-- http://dba.stackexchange.com/questions/10273/how-to-create-an-event-notification-that-runs-a-job-procedure-when-mirroring-sta
-- http://stackoverflow.com/questions/12308099/t-sql-dynamically-filter-xml-on-multiple-conditions/12358926
--History: 1.00 2012/08/27 first release
-- 1.01 2012/09/05 added server-based exclusions and eventsubclass = 0
-- 1.1 2012/09/17 added exclusion_sets which allow multi-condition filtering and improved performance
-- 1.11 2012/10/05 removing the 1=1 as per suggestion by Rusanu;
-- this could cause it to spin forever, blowing out the error_log..and the drive.
-- 1.12 2012/11/14 adding a RETURN in the @@ROWCOUNT. It fails to exit and then hits a COMMIT, causing records
-- in enaudit_error. That was due to the 1.11 change where I no longer use a 1=1.
-- 1.13 2014/01/16 changing ERRORLOG to write the first 500 chars to the CommandText field, as tested in Canada.
SET NOCOUNT ON
DECLARE @message_type NVARCHAR(256),
@message VARBINARY(MAX),
@conversation_handle UNIQUEIDENTIFIER,
@auditdata XML,
@queuing_order BIGINT,
@conversation_group_id UNIQUEIDENTIFIER
BEGIN
BEGIN TRANSACTION;
BEGIN TRY;
WAITFOR (
RECEIVE TOP(1)
@conversation_handle = [conversation_handle], --aka dialog
@conversation_group_id = [conversation_group_id],
@message_type = message_type_name,
@message = message_body,
@queuing_order = queuing_order
FROM dbo.ENAudit_SBQueue --ORDER BY queuing_order --order by doesn't work there.
), TIMEOUT 5000 --we need the timeout so that it won't hold transactions open indefinitely.
IF (@@ROWCOUNT = 0)
BEGIN
ROLLBACK TRANSACTION
--mdb 1.12 2012/11/14 adding a return as otherwise it tries to commit later and fails, causing records in enaudit_error
RETURN
END
SELECT @auditdata = CAST(@message AS XML)
IF @message_type = N'http://schemas.microsoft.com/SQL/Notifications/EventNotification'
-- Dynamically shred the XML and compare to our exclusion table. You should be able to filter on any field.
-- Exclusion set: unique char(2) name. Has to match every condition. Servername is one of the fields handled.
-- Be careful as the filters could impact performance.
and NOT EXISTS --if all active members of the same exclusion_set match, the event is excluded.
(
SELECT * FROM
(
select COUNT(*) AS match_count, exclusion_set
from enaudit_exclusion_list
where exists (
select *
from (
select X.N.value('local-name(.)', 'varchar(128)') as NodeName,
X.N.value('./text()[1]', 'varchar(max)') as NodeValue
from @auditdata.nodes('//*') as X(N)
) T
where T.NodeName = enaudit_exclusion_list.exclusion_type and
T.NodeValue like enaudit_exclusion_list.excluded_value
AND enaudit_exclusion_list.active = 1
)
GROUP BY exclusion_set
) matches_per_set
INNER JOIN
(SELECT COUNT(*) AS total_count, exclusion_set FROM enaudit_exclusion_list WHERE active = 1 GROUP BY exclusion_set) grouped_set
ON match_count = total_count
AND grouped_set.exclusion_set = matches_per_set.exclusion_set
)
BEGIN
INSERT INTO ENAudit_Events
( ServerName ,
queuing_order ,
PostTime ,
StartTime,
EventType ,
SPID ,
LoginName ,
UserName ,
DatabaseName ,
SchemaName ,
ObjectName ,
ObjectType ,
TargetObjectName ,
TargetObjectType ,
CommandText ,
insert_datetime,
message_body_xml
)
--over 128 elements exist, I've chosen the most useful for what I'm doing.
--To get a full list, GROUP BY in the XSD from http://schemas.microsoft.com/sqlserver/2006/11/eventdata/events.xsd
-- More information in EVENTDATA http://msdn.microsoft.com/en-us/library/ms187909.aspx
SELECT
@auditdata.value('(/EVENT_INSTANCE/ServerName)[1]', 'varchar(128)' ) AS ServerName,
@queuing_order AS Queuing_Order,
@auditdata.value('(/EVENT_INSTANCE/PostTime)[1]', 'datetime') AS PostTime,
@auditdata.value('(/EVENT_INSTANCE/StartTime)[1]', 'datetime') AS StartTime,
@auditdata.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(128)' ) as EventType,
@auditdata.value('(/EVENT_INSTANCE/SPID)[1]', 'bigint') AS SPID,
@auditdata.value('(/EVENT_INSTANCE/LoginName)[1]', 'varchar(128)' ) AS LoginName,
@auditdata.value('(/EVENT_INSTANCE/UserName)[1]', 'varchar(128)' ) AS UserName,
@auditdata.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'varchar(128)' ) AS DatabaseName,
@auditdata.value('(/EVENT_INSTANCE/SchemaName)[1]', 'varchar(128)' ) AS SchemaName,
@auditdata.value('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(128)' ) AS ObjectName,
@auditdata.value('(/EVENT_INSTANCE/ObjectType)[1]', 'varchar(128)' ) AS ObjectType,
@auditdata.value('(/EVENT_INSTANCE/TargetObjectName)[1]', 'varchar(128)' ) AS TargetObjectName,
@auditdata.value('(/EVENT_INSTANCE/TargetObjectType)[1]', 'varchar(128)' ) AS TargetObjectType,
--@auditdata.value('(/EVENT_INSTANCE/PropertyName)[1]', 'varchar(128)' ) AS PropertyName,
--@auditdata.value('(/EVENT_INSTANCE/PropertyValue)[1]', 'varchar(128)' ) AS PropertyValue,
--@auditdata.value('(/EVENT_INSTANCE/Parameters)[1]', 'varchar(128)' ) AS Parameters,
CASE @auditdata.value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(128)' )
WHEN 'ERRORLOG' THEN @auditdata.value('/EVENT_INSTANCE[1]/TextData[1]', 'varchar(500)')
ELSE @auditdata.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'varchar(max)' ) END AS CommandText,
GETDATE(),
@auditdata
--Other possibilities for doing a dynamic XML query?
-- http://www.dotnetgenerics.com/Modules/TricksAndTips/SQLServer/DynamicWhereClause.aspx
-- http://www.beefycode.com/post/Expressing-Filter-Queries-as-XML-in-SQL-Server.aspx
-- http://stackoverflow.com/questions/923136/t-sql-filtering-on-dynamic-name-value-pairs
-- http://stackoverflow.com/questions/1729973/filter-sql-queries-on-the-xml-column-using-xpath-xquery
END
else
IF @message_type = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error' --log error messages
BEGIN
WITH XMLNAMESPACES ('http://schemas.microsoft.com/SQL/ServiceBroker/Error' AS ssb)
INSERT INTO ENAudit_Errors ([conversation_group_id], [conversation_handle],
[queuing_order], error_code, error_description, insert_datetime, message_body_raw)
SELECT @conversation_group_id, @conversation_handle, @queuing_order,
@auditdata.value('(//ssb:Error/ssb:Code)[1]', 'INT') AS error_code,
@auditdata.value('(//ssb:Error/ssb:Description)[1]', 'NVARCHAR(4000)') AS error_description,
GETDATE(),
@message
end conversation @conversation_handle --close the conversation if there was an error
END
ELSE
IF @message_type = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
begin
end conversation @conversation_handle;
end
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
declare @xact_state int = xact_state(),
@error_number int = error_number(),
@error_message nvarchar(4000) = error_message(),
@has_rolled_back bit = 0;
if @xact_state = -1
begin
-- Doomed transaction, it must rollback
rollback;
set @has_rolled_back = 1;
end
else if @xact_state = 0
begin
-- transaction was already rolled back (deadlock?)
set @has_rolled_back = 1;
end
insert INTO ENAudit_Errors(
insert_datetime,
error_code,
error_description,
message_body_raw)
values (
getdate(),
@error_number,
@error_message,
@message);
if (@has_rolled_back = 0)
begin
commit;
end
end catch
END
GO
1
따라서 문제 설명에서 내부 활성화를 사용하고 있습니다. sys.dm_broker_activated_tasks에 나열된 것이 있습니까? 활성화 절차는 어떻게됩니까? 여기에 게시 할 수 있습니까? 프로 시저가 모든 메시지를 한 번에 (즉, 한 트랜잭션에서) 처리하려고 할 수 있으며 이는 나쁠 수 있습니다. 또한 수동으로 정품 인증을 실행하는 것을 방해하는 것은 없습니다.
—
벤 툴
포이즌 메시지 (너무 많은 실패)로 인해 큐가 비활성화되었을 수 있습니다. sys.transmission_queue를 쿼리하여보고되는 오류를 알려주십시오. 내 의심이 맞으면 ALTER QUEUE 문을 사용하여 큐를 다시 시작해야합니다.
—
Robert L Davis
@BenThul이 활성화 된 저장 프로 시저 코드를 질문에 추가했습니다. FWIW, 나는 1 = 1을 사용하지 않습니다. 나는 몇 년 전에 Remus Rusanu와 그것에 대해 이야기했으며, 그것을 사용해야 할 이유가없는 방법에 대해 이야기했으며 그에 따라 광산을 수정했습니다. 즉, 속도를 위해 100/1000의 배치를 수행하도록 변경해야 할 것입니다. 그러나 그것이 백업 될 때까지, 그것은 챔피언처럼 일하고 있었기 때문에 나는 그것을 만지기를 싫어했습니다.
—
mbourgon
나는 현재 상황에 루프가 불필요하다는 데 동의하지 않습니다. 이 BOL 기사 ( technet.microsoft.com/en-us/library/… )에 따르면 정품 인증이 자주 트리거되지 않을 수 있습니다. 이것이 트리거 될 때 처리 할 남은 부분이 없을 때까지 각 프로 시저가 메시지를 계속 처리하기를 원하는 이유입니다. 내 두 센트. 당신이 지금 존재하는 구멍에서 자신을 파헤 치기 위해, 당신은
—
벤 툴
while exists (select 1 from dbo.ENAudit_SBQueue) begin exec [dbo].[Parse_EN_Messages]; end
SSMS 와 같은 것을 가짜로 할 수 있습니다.
한 번 봐 가지고 rusanu.com/2008/08/03/understanding-queue-monitors를 하고 적용하는지
—
레무스 Rusanu을