Триггер T-SQL, вызывающий хранимую процедуру SQLCLR, по сравнению с триггером SQLCLR - PullRequest
1 голос
/ 21 июля 2010

Есть ли какие-либо преимущества от вызова хранимой процедуры SQLCLR из обычного триггера T-SQL, а не от немедленного развертывания триггера SQLCLR?

Мне нужно получить уведомление об изменении определенного столбца (StatusID) в очень большой таблице.

В настоящее время используется ряд служб Windows. Каждый контролирует свой собственный StatusID, то есть запрашивает дБ для конкретных StatusID: SELECT a,b,c FROM t WHERE StatusID = @status.

Я хочу попробовать переместить логику из служб в сборку SQLCLR и вызвать их с помощью триггера SQLCLR. Это хорошая идея? Есть лучшие идеи?

Ответы [ 3 ]

1 голос
/ 05 июля 2016

Есть ли какие-либо преимущества для вызова хранимой процедуры SQLCLR из обычного триггера, а не для немедленного развертывания триггера SQLCLR?

Что ж, есть некоторые различия.То, как эти различия связаны с преимуществами или недостатками, зависит от специфики каждой ситуации.

  • Триггер T-SQL, вызывающий объект SQLCLR (хранимая процедура или функция)

    T-Триггеры SQL могут определять, к какой таблице они подключены, с помощью запроса, подобного следующему:

    SELECT ss.[name] AS [SchemaName], so.[name] AS [TableName]
    FROM [sys].[objects] so
    INNER JOIN [sys].[schemas] ss ON ss.[schema_id] = so.[schema_id]
    WHERE so.[object_id] = (SELECT so2.[parent_object_id]
                            FROM [sys].[objects] so2
                            WHERE so2.[object_id] = @@PROCID);
    

    Объект SQLCLR, вызываемый из триггера T-SQL, не будет иметь прямого доступа к псевдо-псевдонимам INSERTED и DELETED-tables (это также верно для хранимых процедур T-SQL или даже вызовов EXEC()).Эти таблицы могут быть скопированы в локальные временные таблицы, которые затем могут быть прочитаны из объекта SQLCLR (или хранимой процедуры T-SQL или вызова EXEC()), но это занимает немного больше времени и требует ввода-вывода для создания таблицы.из псевдотаблицы и снова запишите ее в tempdb.

  • Триггер SQLCLR

    Триггер SQLCLR может взаимодействовать с INSERTED и DELETED псевдотаблицы через динамический SQL (что не может сделать триггер T-SQL).Конечно, если код SQLCLR должен SELECT из псевдотабликов в первую очередь, тогда вам в значительной степени нужно использовать триггер SQLCLR (иначе сделайте глупый трюк copy-pseudo-tables-to-local-temp-tables).

    Триггеры SQLCLR не имеют доступа к @@PROCID (даже при создании SqlConnection с использованием Context Connection = true;), поэтому на самом деле нет простого способа определить, какая таблица изменяласьэто вызвало срабатывание триггера.Я подчеркнул «легко», потому что возможно (хотя я не проверял это) использовать триггер T-SQL, установленный как «первый» триггер в таблице, для установки CONTEXT_INFO с именем таблицы, но затем вы можетеНе используйте CONTEXT_INFO для чего-либо еще.Вероятно, есть еще один способ, который я почти разработал, но еще не тестировал его (когда у меня будет возможность проверить, работает ли он, я постараюсь обновить его со ссылкой на инструкции).

Мне нужно получить уведомление об изменении определенного столбца (StatusID) в очень большой таблице.В настоящее время используется ряд служб Windows.Каждый контролирует свой собственный StatusID, то есть запрашивает дБ для конкретного StatusID: ВЫБЕРИТЕ a, b, c ОТ, ГДЕ StatusID = @ status.

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

CREATE TABLE dbo.TableChangeQueue
(
  TableChangeQueueID INT IDENTITY(-2140000000, 1)
                     NOT NULL
                     CONSTRAINT [PK_TableChangeQueue] PRIMARY KEY,
  [a]                datatype_a,
  [b]                datatype_b,
  [c]                datatype_c
);

Затем используйте обычный триггер T-SQL, чтобы INSERT войти в эту очередь.,Что-то вроде:

INSERT INTO dbo.TableChangeQueue ([a], [b], [c])
    SELECT [a], [b], [c]
    FROM INSERTED;

Тогда каждая служба Windows может читать из таблицы очередей (не большой таблицы).После обработки записей удалите их из таблицы очередей на основе их значений TableChangeQueueID.Вы можете прочитать и удалить их одновременно, используя предложение OUTPUT в операторе DELETE, но если процесс завершится неудачей, вы не захотите потерять возможность повторной попытки их обработки.

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

Здесь много вариантов, но они не могут быть конкретными, не зная, как процессыРабота.Но независимо от этого, главное состоит в том, чтобы отделить обработку измененных StatusID s от операторов DML, поскольку триггеры выполняются внутри внутренней сгенерированной системой транзакции.Вот почему вы не хотите обрабатывать измененные строки немедленно как часть этого триггера, поскольку это может легко увеличить блокировку таблицы, поскольку транзакция не завершится, пока не завершится триггер;и если ошибки триггера, то оператор DML получит откат.

1 голос
/ 22 июля 2010

На мой взгляд, для этого не требуется SQLCLR.Тем не менее, это зависит от того, что вы подразумеваете под «быть уведомленным».Если возможно, я бы использовал обычный триггер и задание агента SQL для уведомления.

0 голосов
/ 24 июля 2010

Если вы вызываете сервисы непосредственно из CLR, вам придется использовать стандартную привязку SOAP, поскольку CLR поддерживает только веб-ссылки в стиле .NET 2.0.

Использование SQL Server Service Broker было бы более надежным решением, но, как вы заметили, это сложно. Цена, которую вы заплатите за использование SQLCLR, заключается в том, что ваши транзакции обновления будут откатываться, если из вашего триггера будет выброшена необработанная ошибка. Также пропускная способность транзакций, безусловно, будет зависеть, если вы будете блокировать вызов службы при каждом обновлении.

...