Как я могу отслеживать поток изменений, вызванных хранимой процедурой в Microsoft SQL Server?

Со следующей таблицей:

CREATE TABLE [Test]
(
    [Id] BIGINT IDENTITY NOT NULL,
    [Name] CHARACTER VARYING(255) NOT NULL,
    [Description] CHARACTER VARYING(MAX) NOT NULL,

    PRIMARY KEY([Id])
);

Я контролирую создание новых записей с помощью хранимой процедуры:

CREATE PROCEDURE [Test_Create]
    @SessionId BINARY(32),
    @Name CHARACTER VARYING(255),
    @Description CHARACTER VARYING(MAX)
AS
BEGIN
    BEGIN TRANSACTION;
        BEGIN TRY
            INSERT INTO [Test] ([Name], [Description])
            VALUES (@Name, @Description);
        END TRY
        BEGIN CATCH
            ROLLBACK TRANSACTION;
            THROW;
        END CATCH
    COMMIT TRANSACTION;
END

У меня есть триггер, который просто регистрирует значения до и после для этой таблицы для всех изменений. Когда вызывается моя хранимая процедура, этот триггер срабатывает и регистрируется в другой таблице. Однако мой триггер, очевидно, не может иметь переменную @SessionId для регистрации сеанса пользователя веб-сайта, вызвавшего вызов хранимой процедуры клиентом SQL, работающим на веб-сервере. Я не хочу использовать SET CONTEXT_INFO, потому что он нестабилен с пулом соединений и планами параллельного выполнения.

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

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

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

Возможно, существует альтернатива извлечению следующей информации и связыванию их вместе для создания контрольного журнала?

  • Пользователь/сеанс веб-сайта, вызвавший вызов хранимой процедуры.
  • Вызванная хранимая процедура и ее параметры
  • Результирующие запросы данных
  • Эффекты запросов (до и после данных)

person Michael J. Gray    schedule 29.04.2014    source источник
comment
Вы не можете просто добавить журнал в Test_Create?   -  person David    schedule 30.04.2014
comment
@David Если я это сделаю, мне нужно будет писать записи журнала для каждой отдельной вставки, обновления или удаления, а затем также выяснять, какими были старые значения. Это добавит много дополнительного кода, который можно решить с помощью триггера. Я думаю, было бы лучше просто выяснить, как соотнести @SessionId из контекста хранимой процедуры с @@SPID из контекста триггера.   -  person Michael J. Gray    schedule 30.04.2014


Ответы (2)


Я бы порекомендовал вам изменить структуру таблицы, чтобы значение @SessionId сохранялось в таблице для создания и изменения.

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

CreatedDateTime DateTime NOT NULL
CreatedBy nvarchar(50) NOT NULL
ModifiedDateTime DateTime NULL
ModifiedBy nvarchar(50) NULL

столбцы

Пользователи входят в систему с аутентификацией Windows, и мы передаем пользовательский domain\username всем хранимым процессам, чтобы его можно было сохранить в столбце CreatedBy или ModifiedBy. Значения CreatedDateTime/ModifiedDateTime устанавливаются хранимыми процедурами.

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

Я думаю, что использование вашего значения @SessionId будет работать так же хорошо.

person DeanOC    schedule 30.04.2014
comment
Что происходит, когда пользователь А изменяет запись, а затем пользователь Б изменяет запись? Ваш проект не поддерживает контрольные журналы и поддерживает только самый последний подход. - person Michael J. Gray; 01.05.2014
comment
Извините, я не ясно выразился. В то время как фактическая таблица показывает только последнего человека, который изменил запись (что полезно для целей отображения), триггер аудита записывает в отдельную базу данных/таблицу аудита каждое отдельное поле, которое изменяется, записывая пользователя/дату изменения/имя таблицы/имя поля. /старое значение /новое значение. Таким образом, если пользователь изменит 20 полей за одно обновление, в таблице журнала будет 20 строк, показывающих, что произошло. - person DeanOC; 01.05.2014
comment
В дополнение к моему последнему комментарию, это хорошо послужило нам в течение последних 7 лет и позволило нам отменить изменения, когда это необходимо, а также провести детективную работу по устранению ошибок или подтвердить/опровергнуть заявление пользователя о том, что я этого не делал. !. Единственным недостатком является то, что наша таблица аудита теперь затмевает реальную базу данных. - person DeanOC; 01.05.2014

Мой первый вопрос: "почему"?

Несколько вариантов, основанных на вашем потенциальном ответе:

Если вам просто любопытно и вы хотите исследовать проблему, вы можете использовать SQL Server Profiler или Database Engine Trace Capture и Trace Replay с правильными событиями регистрации. Это точно скажет вам, какие процедуры были вызваны, почему пользователь и с правильными параметрами.

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

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

person sarin    schedule 30.04.2014
comment
Целью является аудит безопасности и восстановление. Нам нужно знать, какой пользователь на нашем сайте изменил некоторые данные. Мы пытаемся создать функцию восстановления, когда злоумышленник удаляет много контента, и нам нужно приостановить действие пользователя, а затем откатить только то, что он сделал, и поймать любые законные изменения/добавления под перекрестным огнем. Причина, по которой мы хотим контролировать как можно больше данных в базе данных, заключается в том, что у нас есть децентрализованные части этой системы; многие доверенные клиенты подключаются к экземпляру SQL Server и вносят изменения от имени своей пользовательской базы. - person Michael J. Gray; 01.05.2014
comment
В этом случае я бы выбрал средний вариант выше. Создайте таблицы аудита для таблиц, которые можно использовать для отката изменений. Есть несколько способов сделать это. Можно было бы отразить структуру таблицы с помощью таблицы аудита, но это довольно хрупко. Вы можете создать более общую структуру и обновлять ее по мере использования с помощью триггеров, например. Свойство (ID, имя, описание), PropertyChanges (ID, PropertyIdChanged, UserId, Date Changed, ValueBefore, ValueAfter). Это хорошо для аудита, но требуется тщательное обдумывание, чтобы использовать его для возврата данных. Вероятно, возможны и другие решения! - person sarin; 01.05.2014
comment
Итак, я попробовал метод триггера и добавил изменения свойств и все такое. У меня даже откатилось. Трудность, которую я обнаружил с триггерами, заключается в том, что я не могу передать @SessionId триггеру, за исключением SET CONTEXT_INFO, как указано в моем вопросе. - person Michael J. Gray; 01.05.2014
comment
Вместо использования триггеров выполните вставку в хранимую процедуру, а затем вы сможете сохранить идентификатор сеанса в своей таблице аудита, не загрязняя основную таблицу данных. - person sarin; 01.05.2014