Как я могу отслеживать изменения в таблице в базе данных SQL Server, не используя триггеры или каким-либо образом изменяя структуру базы данных? Я предпочитаю среду программирования .NET и C #.
Я хотел бы иметь возможность поддерживать любой SQL Server 2000 SP4 или новее. Мое приложение представляет собой готовую визуализацию данных для продукта другой компании. Наша клиентская база исчисляется тысячами, поэтому я не хочу выдвигать требования, чтобы мы изменяли таблицу сторонних поставщиков при каждой установке.
Под «изменениями в таблице» я подразумеваю изменения данных таблицы, а не изменения структуры таблицы.
В конечном итоге я хотел бы, чтобы изменение запускало событие в моем приложении, вместо того, чтобы проверять изменения через определенный интервал.
С учетом моих требований (отсутствие триггеров или модификации схемы, SQL Server 2000 и 2005) лучшим вариантом действий, по-видимому, является использование BINARY_CHECKSUM
функции в T-SQL . Я планирую реализовать следующее:
Каждые X секунд запускайте следующий запрос:
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*))
FROM sample_table
WITH (NOLOCK);
И сравните это с сохраненным значением. Если значение изменилось, просмотрите таблицу строка за строкой, используя запрос:
SELECT row_id, BINARY_CHECKSUM(*)
FROM sample_table
WITH (NOLOCK);
И сравните возвращенные контрольные суммы с сохраненными значениями.
источник
Ответы:
Взгляните на команду CHECKSUM:
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);
Это будет возвращать одно и то же число при каждом запуске, пока содержимое таблицы не изменилось. См. Мой пост об этом для получения дополнительной информации:
КОНТРОЛЬНАЯ СУММА
Вот как я использовал его для восстановления зависимостей кеша при изменении таблиц:
Зависимость кеша базы данных ASP.NET 1.1 (без триггеров)
источник
К сожалению, CHECKSUM не всегда работает должным образом для обнаружения изменений .
Это только примитивная контрольная сумма и не вычисление циклического контроля избыточности (CRC).
Следовательно, вы не можете использовать его для обнаружения всех изменений, например, симметричные изменения приводят к одной и той же КОНТРОЛЬНОЙ СУММЕ!
E. g. решение с
CHECKSUM_AGG(BINARY_CHECKSUM(*))
всегда будет давать 0 для всех 3 таблиц с разным содержимым: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!
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!
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!
источник
Почему вы не хотите использовать триггеры? Они хороши, если их правильно использовать. Если вы используете их как способ обеспечения ссылочной целостности, тогда они переходят от хороших к плохим. Но если вы используете их для мониторинга, на самом деле они не считаются табу.
источник
Как часто вам нужно проверять наличие изменений и насколько велики (с точки зрения размера строки) таблицы в базе данных? Если вы воспользуетесь
CHECKSUM_AGG(BINARY_CHECKSUM(*))
методом, предложенным Джоном, он просканирует каждую строку указанной таблицы.NOLOCK
Подсказка помогает, но на большой базе данных, вы все еще ударять каждую строку. Вам также нужно будет сохранить контрольную сумму для каждой строки, чтобы вы знали, что она изменилась.Вы думали о том, чтобы взглянуть на это под другим углом? Если вы не хотите изменять схему для добавления триггеров (что имеет смысл, это не ваша база данных), рассматривали ли вы возможность работы с поставщиком приложения, который создает базу данных?
Они могли бы реализовать API, который предоставляет механизм для уведомления дополнительных приложений об изменении данных. Это может быть так же просто, как запись в таблицу уведомлений, в которой указано, какая таблица и какая строка были изменены. Это может быть реализовано с помощью триггеров или кода приложения. С вашей стороны, это не имело бы значения, ваша единственная забота - это периодическое сканирование таблицы уведомлений. Падение производительности базы данных будет намного меньше, чем сканирование каждой строки на предмет изменений.
Сложнее всего убедить поставщика приложения реализовать эту функцию. Поскольку это может быть выполнено полностью через SQL с помощью триггеров, вы можете выполнить большую часть работы за них, написав и протестировав триггеры, а затем передав код поставщику приложения. Если поставщик поддерживает триггеры, это предотвращает ситуацию, когда добавляемый вами триггер непреднамеренно заменяет триггер, предоставленный поставщиком.
источник
К сожалению, я не думаю, что в SQL2000 есть простой способ сделать это. Если вы сузите свои требования до SQL Server 2005 (и более поздних версий), тогда вы в деле. Вы можете использовать
SQLDependency
класс вSystem.Data.SqlClient
. См. Уведомления о запросах в SQL Server (ADO.NET) .источник
Иметь задание DTS (или задание, запускаемое службой Windows), которое выполняется с заданным интервалом. Каждый раз при запуске он получает информацию о данной таблице с помощью системных таблиц INFORMATION_SCHEMA и записывает эти данные в репозиторий данных. Сравните возвращенные данные о структуре таблицы с данными, возвращенными в предыдущий раз. Если он другой, значит, вы знаете, что структура изменилась.
Пример запроса для возврата информации обо всех столбцах в таблице ABC (в идеале перечисление только столбцов из таблицы INFORMATION_SCHEMA, которые вы хотите, вместо использования * select **, как я здесь):
select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'ABC'
Вы будете отслеживать разные столбцы и представления INFORMATION_SCHEMA в зависимости от того, как именно вы определяете «изменения в таблице».
источник
Здесь дикая догадка: если вы не хотите изменять таблицы сторонних разработчиков, можете ли вы создать представление, а затем установить для него триггер?
источник
Проверьте дату последней фиксации. Каждая база данных имеет историю, когда была сделана каждая фиксация. Я считаю, что это стандарт соответствия ACID.
источник