Проверить изменения в таблице SQL Server? - PullRequest
132 голосов
/ 01 августа 2008

Как я могу отслеживать изменения в таблице базы данных SQL Server, не используя триггеры и не изменяя структуру базы данных каким-либо образом? Моя предпочтительная среда программирования - .NET и C #.

Я бы хотел иметь возможность поддерживать любой SQL Server 2000 SP4 или новее. Мое приложение - это визуализация данных для продукта другой компании. Наша клиентская база исчисляется тысячами, поэтому я не хочу предъявлять требования, чтобы мы изменяли таблицу сторонних поставщиков при каждой установке.

Под «изменения в таблице» Я имею в виду изменения в данных таблицы, а не изменения в структуре таблицы.

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


Наилучшим способом действий с учетом моих требований (без триггеров или изменений схемы, SQL Server 2000 и 2005), по-видимому, является использование функции BINARY_CHECKSUM в T-SQL . Я планирую реализовать это так:

Каждые Х секунд запускаются следующие запросы:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*))
FROM sample_table
WITH (NOLOCK);

И сравните это с сохраненным значением. Если значение изменилось, просматривайте таблицу строка за строкой, используя запрос:

SELECT row_id, BINARY_CHECKSUM(*)
FROM sample_table
WITH (NOLOCK);

И сравните возвращенные контрольные суммы с сохраненными значениями.

Ответы [ 8 ]

93 голосов
/ 02 августа 2008

Посмотрите на команду CHECKSUM:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);

Он будет возвращать одно и то же число при каждом запуске, если содержимое таблицы не изменилось. Смотрите мой пост для получения дополнительной информации:

СУММА

Вот как я использовал его для перестройки зависимостей кеша при изменении таблиц:
Зависимость кэша базы данных ASP.NET 1.1 (без триггеров)

30 голосов
/ 30 марта 2011

К сожалению, CHECKSUM не всегда правильно работает для обнаружения изменений .

Это только примитивная контрольная сумма, а не циклическая проверка избыточности (CRC).

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

E. г. решение с CHECKSUM_AGG(BINARY_CHECKSUM(*)) всегда выдаст 0 для всех 3 таблиц с различным содержанием:

<code>
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM 
(
  SELECT 1 as numA, 1 as numB
  UNION ALL
  SELECT 1 as numA, 1 as numB
)  q
-- delivers 0!</p>

<p>SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM 
(
  SELECT 1 as numA, 2 as numB
  UNION ALL
  SELECT 1 as numA, 2 as numB
)  q
-- delivers 0!</p>

<p>SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM 
(
  SELECT 0 as numA, 0 as numB
  UNION ALL
  SELECT 0 as numA, 0 as numB
)  q
-- delivers 0!
25 голосов
/ 01 августа 2008

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

20 голосов
/ 03 августа 2008

Как часто вам нужно проверять наличие изменений и насколько велики (с точки зрения размера строки) таблицы в базе данных? Если вы используете метод CHECKSUM_AGG(BINARY_CHECKSUM(*)), предложенный Джоном, он будет сканировать каждую строку указанной таблицы. Подсказка NOLOCK помогает, но в большой базе данных вы по-прежнему обращаетесь к каждой строке. Вам также нужно будет сохранить контрольную сумму для каждой строки, чтобы сообщить, что она изменилась.

Рассматривали ли вы пойти на это с другой стороны? Если вы не хотите изменять схему для добавления триггеров (что имеет смысл, это не ваша база данных), вы рассматривали возможность работы с поставщиком приложений, который создает базу данных?

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

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

18 голосов
/ 06 августа 2008

К сожалению, я не думаю, что в SQL2000 есть чистый способ сделать это. Если вы сузите свои требования к SQL Server 2005 (и более поздним версиям), то вы в деле. Вы можете использовать класс SQLDependency в System.Data.SqlClient. См. Уведомления о запросах в SQL Server (ADO.NET) .

17 голосов
/ 01 августа 2008

Иметь задание DTS (или задание, запущенное службой Windows), которое выполняется с заданным интервалом. Каждый раз, когда он запускается, он получает информацию о данной таблице с помощью системных таблиц INFORMATION_SCHEMA и записывает эти данные в хранилище данных. Сравните данные, возвращенные относительно структуры таблицы, с данными, возвращенными в предыдущий раз. Если это не так, то вы знаете, что структура изменилась.

Пример запроса для получения информации обо всех столбцах таблицы ABC (в идеале перечисляются только нужные вам столбцы из таблицы INFORMATION_SCHEMA вместо использования * select **, как здесь)

select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'ABC'

Вы будете отслеживать различные столбцы и представления INFORMATION_SCHEMA в зависимости от того, как именно вы определяете «изменения в таблице».

13 голосов
/ 05 августа 2008

Дикая догадка: если вы не хотите изменять таблицы сторонних разработчиков, можете ли вы создать представление и затем включить триггер для этого представления?

6 голосов
/ 24 июля 2014

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...