Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Agent-WD-40
Member

Откуда:
Сообщений: 77
Есть таблица
CREATE TABLE TestNotification (ID int, Value int)
go
Есть триггер
ALTER TRIGGER TestNotificationDmlNotificationInsert
ON dbo.TestNotification FOR INSERT
AS
BEGIN
	DECLARE @messageBody nvarchar
	SELECT @messageBody = (SELECT ID FROM inserted)
	EXEC [SendUpdate] @messageBody
END
go

Есть процедура
ALTER PROCEDURE [SendUpdate]
(
	@messageBody nvarchar
)
AS
BEGIN
	DECLARE @StockDialog uniqueidentifier
		BEGIN DIALOG CONVERSATION @StockDialog
			FROM SERVICE StockSendService
			TO SERVICE 'StockReceiveService'
			ON CONTRACT StockContract
			WITH ENCRYPTION = OFF;	

			SEND ON CONVERSATION @StockDialog 
			MESSAGE TYPE StockMessage (@messageBody)
END
go
Есть вопрос. =) Как это можно представить в более красивом веде.
19 ноя 09, 17:08    [7952504]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Glory
Member

Откуда:
Сообщений: 104760
Красивость в чем мерять будем ?
19 ноя 09, 17:13    [7952532]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Glory
Member

Откуда:
Сообщений: 104760
DECLARE @messageBody nvarchar, например, это эквивалент DECLARE @messageBody nvarchar(1)
19 ноя 09, 17:13    [7952541]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Agent-WD-40
Member

Откуда:
Сообщений: 77
Glory
Красивость в чем мерять будем ?

Красивость хотелось бы померить тем что, нужно ли мне каждый раз начинать новый диалог. Или можно как то использовать существующий. То есть как мне кажется
SEND ON CONVERSATION @StockDialog 
MESSAGE TYPE StockMessage (@messageBody)
Нужно вынести в отдельную процедуру. Но как я передать uniqueidentifier диалога? И как узнать сушествует ли уже открытый диалог или следует начать новый. Вот в чём вопрос.
19 ноя 09, 17:20    [7952594]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Glory
Member

Откуда:
Сообщений: 104760
Хм.
Использовать sys.conversation_endpoints ?
19 ноя 09, 17:24    [7952615]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6723
В добавок надо систему контроля диалога. Чтоб был открыт всегда один, не больше и не меньше.
Соответственно и в обработчике очереди должны контролироваться нештатные ситуации.

Хотя у нас ещё не разу небыло такого, чтоб диалог "падал" (тьфу, тьфу, чтоб не сглазить :) ) на локале

А ещё в inserted может быть несколько строк, а ещё транзакция может откатить ваш SEND MESSAGE и при этом существует ненулевая вероятность, что обработчик очереди "свалится".

Поэтому, если вам надо залогить попытку вставки, то надо извращаться, а если нет, то зачем сразу брокер - регим прямиком в таблу (или оставляем свойство в самой табле), и затем пусть брокер чистит.
Короче, всё зависит от задачи.
19 ноя 09, 22:06    [7953508]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
mike909
Member

Откуда:
Сообщений: 662
Mnior
Поэтому, если вам надо залогить попытку вставки, то надо извращаться, а если нет, то зачем сразу брокер - регим прямиком в таблу (или оставляем свойство в самой табле), и затем пусть брокер чистит.
Короче, всё зависит от задачи.
Для логирования попытки вставки:
CREATE PROCEDURE [dbo].[NotifyReader]
AS
BEGIN
  DECLARE @Res    int,
          @mType  sysname,
          @EType  sysname,
          @hdlg   UNIQUEIDENTIFIER,
          @xml    xml

  set @Res = 0;
  WHILE @Res = 0
  BEGIN
    set @hdlg = NULL;

    BEGIN TRAN

    WAITFOR(
      RECEIVE TOP(1)
        @hdlg = [conversation_handle],
        @mType = message_type_name,
			  @xml =
		      CASE
            WHEN validation = 'X' THEN CAST(message_body AS XML)
            ELSE CAST(N'<none/>' AS XML)
          END
      FROM dbo.Defrag_Queue
    ), TIMEOUT 30000 -- 30 sec.

    if XACT_STATE() = 1
      COMMIT TRAN
    else if XACT_STATE() != 0
      ROLLBACK TRAN

    set @Res = case when @hdlg is not NULL then 0 else -1 end;
    if @Res = 0
    BEGIN  
      if (@mType = 'http://schemas.microsoft.com/SQL/Notifications/EventNotification')
      BEGIN
        SET @EType = @xml.value('(/EVENT_INSTANCE/EventType)[1]', 'sysname')
        if @EType LIKE 'USERCONFIGURABLE_[0-9]'
          print 'Типа запись в таблицу'

        /********** Диалог НЕ ТРОГАЕМ ********/
      END
      ELSE if @mType = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
        END CONVERSATION @hdlg WITH CLEANUP
      ELSE
        END CONVERSATION @hdlg;
    END;
  END;

  RETURN 0
END

GO

CREATE QUEUE [Logger] WITH STATUS = ON, 
  ACTIVATION(STATUS = ON, PROCEDURE_NAME = [NotifyReader], MAX_QUEUE_READERS = 5 , EXECUTE AS N'dbo'  ) ON [PRIMARY] 

GO

CREATE SERVICE [Logger/Processor]  ON QUEUE [Logger] ([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification])

GO

CREATE EVENT NOTIFICATION Log_Information
ON SERVER
FOR USERCONFIGURABLE_0
TO SERVICE 'Logger', 'current database' ;

А в триггере
declare @Type int,
        @Val  varbinary(8000)
set @Type = 82
-- set @Val -- чего хотите
exec sp_trace_generateevent @Type, N'наверно триггер сработал ж-)', @Val

И не страшны RollBack.
Да и за диалогами следить не надо ж-).
И работает у меня уже пару лет и не падает ...

P.S. Красота достигнута ?

Да, самое главное - а зачем триггер то городить ?
Не проще было бы
insert into SomeTable 
OUTPUT INSERTED.ID, INSERTED.Value
INTO TestNotification (ID, Value)
select * from BlaBlaBla
20 ноя 09, 11:13    [7955163]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6723
mike909
sp_trace_generateevent
Красота достигнута?
Хотя мне такое не было нуна, но на заметку взял. Спасибо.
mike909
И работает у меня уже пару лет
Да, мелкомягкие постарались, тоже доволен стабильностью.
Разве что не помню что случалось, после поднятия зеркала.
20 ноя 09, 19:35    [7958724]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Agent-WD-40
Member

Откуда:
Сообщений: 77
mike909,

Спасибо за ответ но вы меня не совсем правильно поняли моя задача в следующем
Есть внешнее приложение которое пишет в базу данных.
Есть база данных с задушенным сервис брокером и тригером на инсерт и абгрейд который посылает первичные ключи изменившихся таблиц в очередь сервис брокера.
И есть толстый клиент на C# который сидит на очереди сервис брокера и при обновлении значений в базе внешней программой пересчитывает бизнес логику. Мой вопрос в том как можно узнать об уже открытом диалоге как верно подметил Mnior "В добавок надо систему контроля диалога. Чтоб был открыт всегда один, не больше и не меньше." В sys.conversation_endpoints я не чего подобного не нащёл.
22 ноя 09, 22:07    [7961703]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6723
Agent-WD-40
клиент на C# который сидит на очереди сервис брокера
А разница? Не уж то вы не можете не закрывать диалог, после RECEIVE-а сообщения?
Хотя я не помню как реализовано ...

Agent-WD-40
В sys.conversation_endpoints я не чего подобного не нащёл.
Как не нашёл? Там же идентификаторы диалогов. Если вы создали один, он один и будет виден для данной очереди.
Если у вас один диалог пажизни - можете железно прописать его guid в процедуре/триггере.
23 ноя 09, 02:17    [7962094]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
mike909
Member

Откуда:
Сообщений: 662
Agent-WD-40
mike909,

Спасибо за ответ но вы меня не совсем правильно поняли моя задача в следующем
Есть внешнее приложение которое пишет в базу данных.
Есть база данных с задушенным сервис брокером .
Т.е. SB выключен ?
Зачем ?
Agent-WD-40
и тригером на инсерт и абгрейд который посылает первичные ключи изменившихся таблиц в очередь сервис брокера.
И есть толстый клиент на C# который сидит на очереди сервис брокера и при обновлении значений в базе внешней программой пересчитывает бизнес логику. Мой вопрос в том как можно узнать об уже открытом диалоге как верно подметил Mnior "В добавок надо систему контроля диалога. Чтоб был открыт всегда один, не больше и не меньше." В sys.conversation_endpoints я не чего подобного не нащёл.

А не проще было бы получить диалоги через WAITFOR( GET CONVERSATION GROUP ....) TimeOut ?
Это на случай получения сообщений от многих сервисов, объединенных в группу, например для обработкаи одной таблицы (пусть каждая таблица, обрабатываемая триггером имеет свой GUID=conversation_group_id).
Или, Ваш случай, WaitFor(RECEIVE ....) TimeOut ?

И зачем Вам знать о каком-то диалоге, да еще и "единственном", хоть убей - не пойму...
Да и конроль какой-то городить -> закрыл диалог и забыл о нем.
23 ноя 09, 09:58    [7962479]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите как можно оптимизировать тригер для работы с service broker  [new]
Agent-WD-40
Member

Откуда:
Сообщений: 77
Mnior
Agent-WD-40
клиент на C# который сидит на очереди сервис брокера
А разница? Не уж то вы не можете не закрывать диалог, после RECEIVE-а сообщения?
Хотя я не помню как реализовано ...

Agent-WD-40
В sys.conversation_endpoints я не чего подобного не нащёл.
Как не нашёл? Там же идентификаторы диалогов. Если вы создали один, он один и будет виден для данной очереди.
Если у вас один диалог пажизни - можете железно прописать его guid в процедуре/триггере.


Да я просто не хочу получить кучу некому не нужных диалогов которые будут висеть в системе. И жрать память. В принципе после RECEIVE можно грохать диалог но зачем потом создавать новый.
Я думаю сделать так повесить в автозагрузку сервера процедуру что то типа этой но с проверкой нет ли уже открытого диалога
CREATE PROCEDURE [SendUpdate]
AS
BEGIN
	DECLARE @dialog_handle AS UNIQUEIDENTIFIER
	BEGIN DIALOG CONVERSATION @dialog_handle
	FROM SERVICE [mlg.MonologService]
	TO SERVICE 'mlg.MonologService'
	ON CONTRACT [mlg.MonologContract]
	WITH
	ENCRYPTION = OFF
END


И тригер на инсер и обгрейд
Create TRIGGER TestNotificationDmlNotificationInsert
ON dbo.TestNotification FOR INSERT
AS
BEGIN
DECLARE @dialog_handle AS UNIQUEIDENTIFIER;
SET @dialog_handle = (select  conversation_handle from sys.conversation_endpoints where is_initiator = 1 and far_service = 'mlg.MonologService' ); 
SEND ON CONVERSATION @dialog_handle
    MESSAGE TYPE [DEFAULT] ((SELECT ID FROM inserted));
END
go


Или это опять бред? Как считаете?
24 ноя 09, 00:44    [7967329]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить