Подтвердить что ты не робот

Как уведомить службу Windows (С#) об изменении таблицы базы данных (sql 2005)?

У меня есть таблица с большой нагрузкой (многие вставки/обновления/удаления) в базе данных SQL2005. Я бы хотел сделать некоторую пост-обработку для всех этих изменений как можно ближе к реальному времени (асинхронно, чтобы не заблокировать таблицу каким-либо образом). Я просмотрел ряд возможных решений, но просто не могу найти подходящее решение, которое кажется правильным.

Тип почтовой обработки также довольно тяжелый, так что служба прослушивателя окон фактически передаст обработку на несколько машин. Однако эта часть приложения уже запущена, полностью асинхронна, а не нужна мне помощь. Я просто хотел упомянуть об этом просто потому, что это повлияло на конструктивное решение, поскольку мы не могли просто загрузить некоторый объект CLR в DB для завершения обработки.

Итак, простая проблема остается: изменения данных в таблице, я хочу сделать некоторую обработку в коде С# на удаленном сервере.

В настоящее время мы придумали использование SQL-триггера, который выполняет "xp_cmdshell", чтобы использовать exe, который вызывает событие, которое слушает служба Windows. Это просто плохо.

Однако другие решения, которые я просматривал в Интернете, также выглядят слишком запутанными. Например, настройка SQLCacheDependancy также требует установки Service broker. Другим возможным решением является использование триггера CLR, который может вызвать веб-сервис, но в этом так много предупреждений в Интернете о том, что это плохой способ сделать это, особенно когда производительность критическая.

В идеале мы не будем отвлекаться на изменения таблицы, но скорее перехватываем вызов внутри нашего приложения и уведомляем об этом службу, к сожалению, хотя у нас есть некоторые устаревшие приложения, вносящие изменения в данные, и мониторинг таблицы является единственным централизованное место на данный момент.

Любая помощь будет наиболее оценена.

Резюме:

  • Необходимо реагировать на изменения данных таблицы в реальном времени
  • Производительность критична.
  • Ожидается большой объем трафика
  • Опрос и запланированные задания не являются опцией (или в режиме реального времени)
  • Реализация сервис-брокера слишком велика (но может быть только решение?)
  • Код CLR еще не исключен, но должен быть перфомант, если предлагается
  • Слушателем/монитором может быть удаленная машина (вероятно, такая же физическая сеть)
4b9b3361

Ответ 1

У вас действительно не так много способов обнаружить изменения в SQL 2005. Вы уже указали большинство из них.

Уведомления о запросах. Это технология, которая управляет SqlDependency и ее производными, вы можете прочитать более подробную информацию о The Mysterious Notification. Но QN предназначен для недействительности результатов, а не для активного уведомления о содержании изменений. Вы только знаете, что таблица имеет изменения, не зная, что изменилось. В занятой системе это не сработает, так как уведомления будут поступать довольно долго.

Чтение журнала. Это то, что использует транзакционная репликация, и является наименее интрузивным способом обнаружения изменений. К сожалению, доступно только для внутренних компонентов. Даже если вам удастся понять формат журнала, проблема в том, что вам нужна поддержка от механизма, чтобы пометить журнал как "используемый", пока вы его не прочитаете, или он может быть перезаписан. Только транзакционная репликация может выполнять такую ​​специальную маркировку.

Сравнение данных. Положитесь на столбцы timestamp для обнаружения изменений. Является также натягивающим, довольно интрузивным и имеет проблемы с обнаружением удалений.

Уровень приложения. Это лучший вариант в теории, если только изменения не происходят за пределами данных приложения, и в этом случае он рушится. На практике всегда происходят изменения вне области применения.

Триггеры. В конечном счете, это единственный жизнеспособный вариант. Все механизмы изменения, основанные на триггерах, работают одинаково, они приостанавливают уведомление об изменении компоненту, который контролирует очередь.

Всегда есть предложения по строгому синхронному уведомлению (через xp_cmdshell, xp_olecreate, CLR, уведомлять с WCF, вы называете это), но все эти схемы не работают на практике, потому что они в корне ошибочны:
 - они не учитывают согласованность транзакций и откаты

 - они вводят зависимости доступности (система OLTP не может действовать, если уведомляемый компонент не подключен)
 - они выполняются ужасно, так как каждая операция DML должна ждать завершения вызова RPC какой-либо формы

Если триггеры на самом деле не активно уведомляют слушателей, но только в очереди уведомлений, есть проблема в мониторинге очереди уведомлений (когда я говорю "очередь", я имею в виду любую таблицу, которая действует как очередь). Мониторинг предполагает вытягивание новых записей в очереди, что означает правильную балансировку частоты проверок с нагрузкой изменений и реагирование на нагрузки. Это совсем не тривиально, на самом деле это очень сложно. Однако на SQL-сервере есть один оператор, который имеет семантику для блокировки, без вытягивания, до тех пор, пока изменения не станут доступными: WAITFOR (RECEIVE). Это означает Service Broker. Вы упомянули SSB несколько раз в своем посте, но вы, верно, боитесь развернуть его из-за большого неизвестного. Но реальность такова, что она, безусловно, лучше всего подходит для описанной вами задачи.

Вам не нужно развертывать полную архитектуру SSB, где уведомление доставляется до удаленной службы (для чего требуется удаленный экземпляр SQL, даже Express). Все, что вам нужно сделать, это отделить момент, когда обнаружение изменения (триггер DML) с момента подачи уведомления (после того, как изменение выполнено). Для этого вам нужна только локальная SSB-очередь и служба. В триггере вы ОТПРАВИТЬ уведомление об изменении для местной службы. После совершения первоначальной транзакции DML процедура обслуживания активирует и доставляет уведомление, используя, например, CLR. Вы можете увидеть пример чего-то подобного в Асинхронный T-SQL.

Если вы спуститесь по этому пути, вам понадобятся некоторые трюки, необходимые для достижения высокой пропускной способности, и вы должны понимать концепцию упорядоченной доставки сообщений в SSB. Я рекомендую вам прочитать эти ссылки:

О средствах обнаружения изменений, SQL 2008, по-видимому, добавляет новые параметры: Изменить отслеживание данных и отслеживание изменений, Я подчеркиваю "по-видимому", поскольку они не являются новыми технологиями. CDC использует программу чтения журналов и основывается на существующих механизмах репликации транзакций. CT использует триггеры и очень похож на существующие механизмы репликации Merge. Они оба предназначены для периодически подключаемых систем, которые необходимо синхронизировать и, следовательно, не подходят для уведомления об изменении в режиме реального времени. Они могут заполнять таблицы изменений, но вам остается задача отслеживать эти таблицы для изменений, которые находятся именно там, где вы начали.

Ответ 2

Это можно сделать разными способами. ниже метод прост, так как вы не хотите использовать триггеры CLR и sqlcmd.

  • Вместо использования триггеров CLR вы можете создать обычный триггер insert, который обновляет выделенную таблицу отслеживания для каждой вставки.

  • И создайте специализированную службу окон, которая активно опросит таблицу отслеживания и обновит удаленную службу, если есть какие-либо изменения в данных и настроен статус в таблице отслеживания (так что его больше не будет выбрано).

EDIT:

Я думаю, что службы синхронизации Microsoft для ADO.Net могут работать на вас. Ознакомьтесь с приведенными ниже ссылками. Это может помочь вам

Ответ 3

В подобных обстоятельствах мы используем триггер CLR, который пишет сообщения в очередь (MSMQ). Служба, написанная на С#, контролирует очередь и выполняет пост-обработку. В нашем случае все делается на одном сервере, но вы можете отправлять эти сообщения непосредственно в удаленную очередь на другой машине, полностью обходя "локальный слушатель".

Код, вызываемый из триггера, выглядит следующим образом:

public static void SendMsmqMessage(string queueName, string data)
{
    //Define the queue path based on the input parameter.
    string QueuePath = String.Format(".\\private$\\{0}", queueName);

    try
    {
        if (!MessageQueue.Exists(QueuePath))
            MessageQueue.Create(QueuePath);

        //Open the queue with the Send access mode
        MessageQueue MSMQueue = new MessageQueue(QueuePath, QueueAccessMode.Send);

        //Define the queue message formatting and create message
        BinaryMessageFormatter MessageFormatter = new BinaryMessageFormatter();
        Message MSMQMessage = new Message(data, MessageFormatter);

        MSMQueue.Send(MSMQMessage);
    }
    catch (Exception x)
    {
        // async logging: gotta return from the trigger ASAP
        System.Threading.ThreadPool.QueueUserWorkItem(new WaitCallback(LogException), x);
    }
}

Ответ 4

Поскольку вы сказали, что на этой таблице много вложений, пакетная обработка может соответствовать лучше.

Почему просто создайте запланированное задание, которое обрабатывает новые данные, идентифицированные столбцом флага, и обрабатывает данные в больших кусках?