Обнаружение изменений в таблице SQL Server


13

В моем приложении с БД, работающей на SQL Server 2012, у меня есть задание (запланированное задание), которое периодически выполняет дорогостоящий запрос и записывает результаты в таблицу, которую впоследствии может запрашивать приложение.

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

У меня есть следующие идеи:

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

Однако мне бы очень хотелось узнать, есть ли легкий способ обнаружения изменений в таблице без явного отслеживания записей. Могу ли я, например, получить «текущую» ROWVERSIONтаблицу или что-то в этом роде?

Ответы:


14

Нет, их нет. Любое отслеживание «Последнее обновление в» может привести к серьезной проблеме производительности, поскольку все обновления из всех транзакций будут пытаться обновить одну запись, отслеживающую «Последнее обновление в». Это фактически означало бы, что только одна транзакция может обновлять таблицу в любой момент, и все остальные транзакции должны ждать, пока первая из них будет зафиксирована . Полная Сериализация. Число администраторов / разработчиков, готовых смириться с таким снижением производительности только для того, чтобы знать, когда произошло последнее обновление, вероятно, невелико.

Таким образом, вы застряли, чтобы справиться с этим через пользовательский код. Это означает триггеры, поскольку альтернатива (обнаружение по записям журнала) является прерогативой, зарезервированной только для репликации транзакций (или это альтернативное эго CDC ). Имейте в виду, что если вы попытаетесь отследить его через столбец «последнее обновление в», то вы столкнетесь именно с проблемой сериализации, упомянутой выше. Если параллелизм обновления важен, вам придется использовать механизм очереди (триггер использует INSERT, а затем процесс объединяет вставленные значения, чтобы сформулировать «последнее обновление в»). Не пытайтесь обманывать с каким-нибудь «умным» решением, например, подкрадываться к текущей личности или искать sys.dm_db_index_usage_stats . А также столбец «updated_at» для каждой записи, как у временных меток Rails,

Есть ли «легкая» альтернатива? На самом деле он есть, но трудно сказать, будет ли он работать для вас, и трудно понять его правильно: уведомления о запросах . Query Notification делает именно это, он настроит уведомление, если какие-либо данные изменились, и вам нужно обновить ваш запрос. Хотя большинство разработчиков знакомы только с его воплощением .Net как SqlDependency, Query Notification можно использовать как долговременный постоянный механизм для обнаружения изменений данных. По сравнению с истинным отслеживанием изменений он будет действительно легковесным, а его семантика ближе к вашим потребностям (что-то, что-нибудь изменилось, поэтому вам нужно повторно выполнить запрос).

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


Так зачем Microsoft беспокоиться о создании sys.dm_db_index_usage_stats, если на информацию, предоставленную ею, нельзя положиться?
Крейг Эфрейн

Это не DMV, предназначенная для отслеживания изменений . Очень надежный для предназначенной цели, которая является настройкой производительности.
Ремус Русану

8

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

Есть два механизма SQL Server, которые могут вам помочь. Ваше окончательное решение может быть гибридом двух.

Отслеживание изменений . SQL Server имеет возможность размещать определенные таблицы под наблюдением, записывать только те строки, которые были изменены (по значению их первичного ключа), и какие это были изменения (Вставить, Обновить или Удалить). После настройки обнаружения изменений для набора таблиц облегченный запрос может сообщить вам, были ли внесены какие-либо изменения в таблицу с момента последней проверки. Накладные расходы примерно такие же, как и на поддержание дополнительного простого индекса.

Rowversion / timestamp . Это 8-байтовый тип столбца varbinary (преобразуемый в BigInt), который увеличивается по всей базе данных всякий раз, когда строка, содержащая его, вставляется или обновляется (это не помогает при удалении). Если вы проиндексировали эти столбцы, вы могли бы легко определить, изменились ли данные строки, сравнив значение MAX (отметка времени) с его значением с момента последней оценки. Поскольку значение монотонно увеличивается, это даст вам надежное указание на то, что данные изменились, если новое значение больше, чем в прошлый раз, когда вы его проверяли.


7

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

Для обновляемых строк добавьте «грязный» флаг. Он будет иметь три значения - чистый, грязный и удаленный. В повседневных запросах нужно будет пропустить строки с установленным флагом «удалено». Это будет дорого в обслуживании, тестировании и во время выполнения. После большого запроса вы упоминаете, что все строки, помеченные для удаления, должны быть удалены, а флаг сброшен для всех остальных. Это не будет хорошо масштабироваться.

Более легкой альтернативой для сбора данных изменений является отслеживание изменений . Он не скажет вам, какие значения изменились, только то, что строка изменилась с момента последнего запроса. Встроенные функции облегчают поиск измененных значений и управление отслеживанием. Мы успешно использовали CT для обработки около 100 000 изменений в день в таблице 100 000 000 строк.

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

В контексте вопроса OP, QN будет иметь преимущество, заключающееся в том, что он требует минимальных накладных расходов и требует небольших затрат времени выполнения. Это может быть значительное усилие, чтобы установить и поддерживать строгий режим подписки-сообщения-реагирования. Поскольку таблица данных велика, вероятно, в ней будут частые изменения, а это означает, что уведомление может срабатывать в большинстве циклов обработки. Поскольку нет указаний на то, что изменилась инкрементная обработка дельт, будет невозможно, как это было бы с CT или CDC. Накладные расходы из-за ложных срабатываний являются утомительными, но даже в худшем случае дорогой запрос не нужно выполнять чаще, чем в настоящее время.


3

SqlTableDependency

SqlTableDependency - это компонент реализации высокого уровня для доступа к уведомлениям, содержащим значения записей таблицы в базе данных SQL Server.

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

В чем разница с .NET SqlDepenency?

Основное отличие состоит в том, что SqlTableDependency отправляет события, содержащие значения для вставленной, измененной или удаленной записи, а также операцию DML (вставка / удаление / обновление), выполняемую в таблице: SqlDepenency не сообщает, какие данные были изменены в таблицы базы данных, они только говорят, что что-то изменилось.

Посмотрите на проект GITHUB .


1

Если ожидаемые обновления влияют на индекс (и только если), вы можете использовать системную таблицу sys.dm_db_index_usage_statsдля определения последнего обновления индекса в рассматриваемой таблице. Вы бы использовали last_user_updateполе.

Например, чтобы получить самые последние обновленные таблицы:

select
    object_name(object_id) as OBJ_NAME, *
from
    sys.dm_db_index_usage_stats
where
    database_id = db_id(db_name())
order by
    dm_db_index_usage_stats.last_user_update desc

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

select
    case when count(distinct object_id) > 0 then 1 else 0 end as IS_CHANGED
from
    sys.dm_db_index_usage_stats
where
    database_id = db_id(db_name())
    and object_id = object_id('MY_TABLE_NAME')
    and last_user_update > '2016-02-18'

Что вы думаете о комментариях Ремуса выше? «Не пытайтесь обманывать с помощью какого-нибудь« умного »решения, например, подкрадываться к текущей личности или искать sys.dm_db_index_usage_stats.» (См. Также его комментарий ниже его ответа.)
Фабиан Шмид

1
@FabianSchmied Интересно - я не видел, чтобы, когда я добавил свой ответ, я не смог найти ничего, кроме автора Ремуса, который бы указывал, что он ненадежен для этого варианта использования; на странице MS dm_db_index_operational_statsотображаются проблемы (очищенные при очистке кэша метаданных), но не для dm_db_index_usage_stats. Единственная проблема, которую я обнаружил, была с перестроениями индекса, перезапусками сервера и отсоединением базы данных, очищающими статистику использования, и это, похоже, не применялось здесь. Было бы интересно увидеть обоснованную информацию по этому вопросу.
Джефф
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.