私はこの質問の順序でこの質問をしています TCP T-SQLを使用して文字列を送信できますか?
Remus Rusanuが私の問題に最適なソリューションであると思われるものを公開します。
これまでのところ、DATABASE_MIRRORING_STATE_CHANGEの通知イベントを作成するために何が必要だと思いますか?
トリガーされたときにタイムスタンプと通知からのIDを格納する行をテーブルに挿入するときに、このイベント通知を作成するにはどうすればよいですか。
これまでのところ、IDごとに1つのアラートを設定し、それぞれが次のようなジョブを実行しています(この例はID = 1の場合です):
DECLARE @state AS varchar(50);
SELECT @state = mirroring_state_desc FROM SYS.database_mirroring WHERE mirroring_guid IS NOT NULL;
IF (@state IS null) SET @state = ' ';
INSERT INTO MirroringAlerts (DateTime, alertID, alertDesc, Sync, alertCreator) values (SYSDATETIME(), 1, 'Principal synchronized with W ', @state, @@SERVERNAME)
基本的に私はこのデータベースに内部ログを作成しています:
CREATE TABLE [dbo].[MirroringAlerts](
[DateTime] [datetime] NOT NULL,
[alertID] [smallint] NOT NULL,
[alertDesc] [nchar](50) NOT NULL,
[Sync] [nchar](12) NOT NULL,
[alertCreator] [nchar](128) NULL
) ON [PRIMARY]
しかし、このように...アラートが十分に速くトリガーされていません...だから、情報を失っています...
データベースミラーリングの状態変更イベント に対して イベントの作成通知 を使用してこの動作をプログラムする方法を教えていただけますか?
宜しくお願いします
ステップ1:通知を受け取るサービスとそのキューを作成します。
use msdb;
go
create queue dbm_notifications_queue;
create service dbm_notification_service
on queue dbm_notifications_queue
([http://schemas.Microsoft.com/SQL/Notifications/PostEventNotification]);
go
create event notification dbm_notifications
on server
for database_mirroring_state_change
to service N'dbm_notification_service', N'current database';
go
msdb
を使用していることに注意してください。これは偶然ではありません。サーバーレベルのイベント通知はmsdb
から送信されるため、msdb
にも反対の会話エンドポイント(ターゲット)を作成すると、宛先サービスとキューも必要になることを意味します。 msdb
にデプロイされます。
ステップ2:イベント通知処理手順を作成します。
use msdb;
go
create table dbm_notifications_errors (
incident_time datetime not null,
session_id int not null,
has_rolled_back bit not null,
[error_number] int not null,
[error_message] nvarchar(4000) not null,
[message_body] varbinary(max));
create clustered index cdx_dbm_notifications_errors
on dbm_notifications_errors (incident_time);
go
create table mirroring_alerts (
alert_time datetime not null,
start_time datetime not null,
processing_time datetime not null,
database_id smallint not null,
database_name sysname not null,
[state] tinyint not null,
[text_data] nvarchar(max),
event_data xml not null);
create clustered index cdx_mirroring_alerts
on mirroring_alerts (alert_time);
go
create procedure dbm_notifications_procedure
as
begin
declare @dh uniqueidentifier, @mt sysname, @raw_body varbinary(max), @xml_body xml;
begin transaction;
begin try;
receive top(1)
@dh = conversation_handle,
@mt = message_type_name,
@raw_body = message_body
from dbm_notifications_queue;
if N'http://schemas.Microsoft.com/SQL/Notifications/EventNotification' = @mt
begin
set @xml_body = cast(@raw_body as xml);
-- shred the XML and process it accordingly
-- IMPORTANT! IMPORTANT!
-- DO NOT LOOK AT sys.database_mirroring
-- The view represents the **CURRENT** state
-- This message reffers to an **EVENT** that had occured
-- the current state may or may no be relevant for this **PAST** event
declare @alert_time datetime
, @start_time datetime
, @processing_time datetime = getutcdate()
, @database_id smallint
, @database_name sysname
, @state tinyint
, @text_data nvarchar(max);
set @alert_time = @xml_body.value (N'(//EVENT_INSTANCE/PostTime)[1]', 'DATETIME');
set @start_time = @xml_body.value (N'(//EVENT_INSTANCE/StartTime)[1]', 'DATETIME');
set @database_id = @xml_body.value (N'(//EVENT_INSTANCE/DatabaseID)[1]', 'SMALLINT');
set @database_name = @xml_body.value (N'(//EVENT_INSTANCE/DatabaseName)[1]', 'SYSNAME');
set @state = @xml_body.value (N'(//EVENT_INSTANCE/State)[1]', 'TINYINT');
set @text_data = @xml_body.value (N'(//EVENT_INSTANCE/TextData)[1]', 'NVARCHAR(MAX)');
insert into mirroring_alerts (
alert_time,
start_time,
processing_time,
database_id,
database_name,
[state],
text_data,
event_data)
values (
@alert_time,
@start_time,
@processing_time,
@database_id,
@database_name,
@state,
@text_data,
@xml_body);
end
else if N'http://schemas.Microsoft.com/SQL/ServiceBroker/Error' = @mt
begin
set @xml_body = cast(@raw_body as xml);
DECLARE @error INT
, @description NVARCHAR(4000);
WITH XMLNAMESPACES ('http://schemas.Microsoft.com/SQL/ServiceBroker/Error' AS ssb)
SELECT @error = CAST(@xml_body AS XML).value('(//ssb:Error/ssb:Code)[1]', 'INT'),
@description = CAST(@xml_body AS XML).value('(//ssb:Error/ssb:Description)[1]', 'NVARCHAR(4000)');
insert into dbm_notifications_errors(
incident_time,
session_id,
has_rolled_back,
[error_number],
[error_message],
[message_body])
values (
getutcdate(),
@@spid,
0,
@error,
@description,
@raw_body);
end conversation @dh;
end
else if N'http://schemas.Microsoft.com/SQL/ServiceBroker/EndDialog' = @mt
begin
end conversation @dh;
end
commit;
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 dbm_notifications_errors(
incident_time,
session_id,
has_rolled_back,
[error_number],
[error_message],
[message_body])
values (
getutcdate(),
@@spid,
@has_rolled_back,
@error_number,
@error_message,
@raw_body);
if (@has_rolled_back = 0)
begin
commit;
end
end catch
end
go
Service Brokerプロシージャの記述は、ありふれたコードではありません。特定の基準に従う必要があり、流砂地域に迷い込むのは非常に簡単です。このコードはいくつかの良い習慣を示しています:
Error
およびEndDialog
メッセージを適切に処理します。そうしないと、ハンドルリークが発生します(sys.conversation_endpoints
が大きくなります)。RECEIVE
の後にcheck @@ rowcountをチェックしていますが、これで問題ありません。このサンプルコードは、メッセージ名チェック(メッセージがないことはNULLメッセージタイプ名を意味する)に依存し、そのケースを暗黙的に処理します。さらに、このコードは、当面のタスク(DBMの監視)に関して、いくつかの優れた実践コードも実行します。
post_time
(通知がいつ送信されたか)、start_time
(は通知をトリガーするアクションがいつ開始されたかを区別します?)およびprocessing_time
(通知はいつ処理されましたか?)。 post_time
とstart_time
は同一または非常に近い可能性がありますが、processing_time
はpost_time
から数秒、数時間、数日離れている場合があります。通常、監査で興味深いのはpost_time
です。post_time
とprocessing_time
は異なるため、通知がアクティブ化されたプロシージャのDBMモニタリングタスクsys.database_mirroring
ビューを確認するビジネスはない 。そのビューには、処理の瞬間のcurrent状態が表示されます。これは、イベントに関連する場合と関連しない場合があります。イベントがポストされてから長い時間(メンテナンスダウンタイムを考えて)処理が発生する場合、問題は明白ですが、DBMの状態が非常に速く変化し、2つ(またはそれ以上)のイベントが行(これは頻繁に発生します):この状況では、投稿したコードのように、イベントが発生したときにイベントを監査しますが、現在のfinal状態を記録します。そのような監査を読むと、後で非常に混乱する可能性があります。手順3:プロシージャをキューにアタッチします。
alter queue dbm_notifications_queue
with activation (
status=on,
procedure_name = [dbm_notifications_procedure],
max_queue_readers = 1,
execute as owner);
第6章を読んだ後、「Pro SQL Server 2008ミラーリング」を購入する必要がありました。これを行う手順は次のとおりです。
service Brokerが有効になっているかどうかを確認する
SELECT CASE is_broker_enabled
WHEN 1 Then 'Enabled'
ELSE 'Disabled'
END
FROM sys.databases
WHERE name = 'DataBaseName'
そうでない場合は、実行します
ALTER DATABASE DataBaseName set ENABLE_BROKER;
通知イベントが到着したときにトリガーされるストアドプロシージャを作成します。
CREATE PROCEDURE dbo.dba_MirroringStateChanged
AS
DECLARE @Message XML,
@DBName sysname,
@MirrorStateChange INT,
@ServerName sysname,
@PostTime datetime,
@SPID INT,
@TextData NVARCHAR(500),
@DatabaseID INT,
@TransactionsID INT,
@StartTime datetime;
SET NOCOUNT ON;
-- Receive first unread message in service broker queue
RECEIVE TOP (1)
@Message = CAST(message_body AS XML)
FROM DBMirrorQueue;
BEGIN TRY
-- Parse state change and database affected
-- 7 or 8 = database failing over,
--11 = synchronizing,
--1 or 2 = synchronized
SET @MirrorStateChange =
@Message.value('(/EVENT_INSTANCE/State)[1]', 'int');
SET @DBName =
@Message.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'sysname');
SET @ServerName =
@Message.value('(/EVENT_INSTANCE/ServerName)[1]', 'sysname');
SET @PostTime =
@Message.value('(/EVENT_INSTANCE/PostTime)[1]', 'datetime');
SET @SPID = @Message.value('(/EVENT_INSTANCE/SPID)[1]', 'int');
SET @TextData =
@Message.value('(/EVENT_INSTANCE/TextData)[1]', 'nvarchar(500)');
SET @DatabaseID =
@Message.value('(/EVENT_INSTANCE/DatabaseID)[1]', 'int');
SET @TransactionsID =
@Message.value('(/EVENT_INSTANCE/TransactionsID)[1]', 'int');
SET @StartTime =
@Message.value('(/EVENT_INSTANCE/StartTime)[1]', 'datetime');
END TRY
BEGIN CATCH
PRINT 'Parse of mirroring state change message failed.';
END CATCH
IF (@MirrorStateChange IN (1,2,3,4,5,6,7,8,9,10,11,12,13))
BEGIN
DECLARE @state AS varchar(50);
SELECT @state = mirroring_state_desc FROM SYS.database_mirroring WHERE mirroring_guid IS NOT NULL;
IF (@state IS null) SET @state = ' ';
INSERT INTO MirroringAlerts (DateTime, alertID, alertDesc, Sync, alertCreator) values (SYSDATETIME(), @MirrorStateChange , @TextData , @state, @SERVERNAME);
END
キューを作成します。これは、サービスと、トリガーするストアドプロシージャの間の仲介役になります。
-- Create Queue if not exists
IF NOT EXISTS (SELECT 1
FROM sys.service_queues
WHERE name = 'DBMirrorQueue')
BEGIN
CREATE QUEUE DBMirrorQueue
WITH ACTIVATION (
PROCEDURE_NAME = dbo.dba_MirroringStateChanged,
MAX_QUEUE_READERS = 1,
EXECUTE AS OWNER);
END
イベントに関連付けられるサービスを作成する
-- Create Service if not exists
IF NOT EXISTS (SELECT 1
FROM sys.services
WHERE name = 'DBMirrorService')
BEGIN
CREATE SERVICE DBMirrorService
ON QUEUE DBMirrorQueue ([http://schemas.Microsoft.com/SQL/Notifications/PostEventNotification]);
END
ルートを作成する
-- Create Route if not exists
IF NOT EXISTS (SELECT 1
FROM sys.routes
WHERE name = 'DBMirrorRoute')
BEGIN
CREATE ROUTE DBMirrorRoute
WITH SERVICE_NAME = 'DBMirrorService',
ADDRESS = 'Local';
END
次に、イベント通知を作成します
-- Create Event Notification if not exists
IF NOT EXISTS (SELECT 1
FROM sys.server_event_notifications
WHERE name = 'DBMirrorStateChange')
BEGIN
CREATE EVENT NOTIFICATION DBMirrorStateChange
ON SERVER
FOR DATABASE_MIRRORING_STATE_CHANGE
TO SERVICE 'DBMirrorService', 'current database';
END