Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
Применимо к:SQL Server
База данных
SQL AzureУправляемый экземпляр
SQL AzureБаза данных SQL в Microsoft Fabric
Приложения, в которых используется отслеживание изменений, должны иметь возможность получать отслеженные изменения, применять эти изменения к другому хранилищу данных и обновлять базу данных-источник. В этой статье описывается, как выполнять эти задачи, а также роль, которую отслеживание изменений играет при резервном переключении, когда необходимо восстановить базу данных из резервной копии.
Получайте изменения с помощью функций отслеживания изменений
Описывает, как использовать функции отслеживания изменений, чтобы получить изменения и сведения об изменениях, произведенных в базе данных.
Сведения о функциях отслеживания изменений
Чтобы получить изменения из базы данных и сведения об этих изменениях, приложения могут использовать следующие функции.
CHANGETABLE(CHANGES ...)функцияЭта функция, возвращающая набор строк, используется для запроса информации об изменениях. Функция запрашивает данные, хранящиеся во внутренних таблицах отслеживания изменений. Она возвращает результирующий набор, содержащий первичные ключи измененных строк, а также другие сведения: операцию, число обновленных столбцов и версии строк.
CHANGETABLE(CHANGES ...)принимает последнюю версию синхронизации в качестве аргумента. Версию последней синхронизации можно получить с помощью переменной@last_synchronization_version. Семантика последней версии синхронизации выглядит следующим образом.Вызывающий клиент получает сведения обо всех изменениях, происшедших до момента последней синхронизированной версии включительно.
CHANGETABLE(CHANGES ...)Поэтому возвращаются все изменения, произошедшие после последней версии синхронизации.
На следующем рисунке показано, как CHANGETABLE(CHANGES ...) использовать для получения изменений.
В этом примере клиент A последний синхронизирован в 9:30, а клиент B последний синхронизирован в 10:30. В 10:00 и снова в 11:00 были внесены некоторые изменения в данные. Эти отслеживаемые изменения приведены в следующем примере.
CHANGETABLE(CHANGES...) Вывод — 11:30 AM
Клиент A был синхронизирован последний раз в 9:30 утра.
Product ID |
Операция | Столбцы |
|---|---|---|
| 139 | Обновить | Имя, цена |
| 140 | Удалить | - |
| 141 | Вставить | - |
Клиент B был последний раз синхронизирован в 10:30.
Product ID |
Операция | Столбцы |
|---|---|---|
| 139 | Обновить | Цена |
| 140 | Удалить | - |
| 141 | Обновить | Цена |
CHANGE_TRACKING_CURRENT_VERSION()функцияИспользуется для получения текущей версии, которая будет использоваться при следующем запросе изменений. Эта версия представляет версию последней зафиксированной транзакции.
CHANGE_TRACKING_MIN_VALID_VERSION()функцияИспользуется для получения минимальной допустимой версии, которую может иметь клиент и все еще получать допустимые результаты от
CHANGETABLE(). Клиент должен сравнить последнюю версию синхронизации со значением, возвращенным этой функцией. Если последняя версия синхронизации меньше версии, возвращаемой этой функцией, клиент не сможет получить действительные результаты изCHANGETABLE()и ему придется повторно инициализировать.
Получение исходных данных
Прежде чем приложение в первый раз получит изменения, оно должно выполнить запрос для получения первоначальных данных и версии синхронизации. Приложение должно получить соответствующие данные непосредственно из таблицы, а затем использовать CHANGE_TRACKING_CURRENT_VERSION() для получения начальной версии. Эта версия будет передана CHANGETABLE(CHANGES ...) в первый раз, когда будут получены изменения.
В следующем примере показано получение первоначальной версии синхронизации и первоначального набора данных.
declare @synchronization_version bigint;
-- Obtain the current synchronization version. This will be used next time that changes are obtained.
SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION();
-- Obtain initial data set.
SELECT
P.ProductID, P.Name, P.ListPrice
FROM
SalesLT.Product AS P;
Использование функций отслеживания изменений для получения изменений
Чтобы получить измененные строки для таблицы и сведения об изменениях, используйте CHANGETABLE(CHANGES...). Например, следующий запрос получает изменения для SalesLT.Product таблицы.
declare @last_synchronization_version bigint;
SELECT
CT.ProductID, CT.SYS_CHANGE_OPERATION,
CT.SYS_CHANGE_COLUMNS, CT.SYS_CHANGE_CONTEXT
FROM
CHANGETABLE(CHANGES SalesLT.Product, @last_synchronization_version) AS CT;
Как правило, клиенту нужно получить последние данные строки, а не просто первичные ключи. Таким образом, приложение объединит результаты из CHANGETABLE(CHANGES ...) с данными в таблице пользователя. Например, следующий запрос соединяется с таблицей SalesLT.Product , чтобы получить значения столбцов Name и ListPrice . Обратите внимание на использование OUTER JOIN. Это требуется, чтобы убедиться, что возвращаются сведения об изменениях в строках, удаленных из пользовательской таблицы.
SELECT
CT.ProductID, P.Name, P.ListPrice,
CT.SYS_CHANGE_OPERATION, CT.SYS_CHANGE_COLUMNS,
CT.SYS_CHANGE_CONTEXT
FROM
SalesLT.Product AS P
RIGHT OUTER JOIN
CHANGETABLE(CHANGES SalesLT.Product, @last_synchronization_version) AS CT
ON
P.ProductID = CT.ProductID;
Чтобы получить версию, которая будет использоваться в следующем перечислении изменений, используется функция CHANGE_TRACKING_CURRENT_VERSION(), как показано в следующем примере.
SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION();
Когда приложение получает изменения, оно должно использовать как функцию CHANGETABLE(CHANGES...), так и CHANGE_TRACKING_CURRENT_VERSION(), как показано в следующем примере.
-- Obtain the current synchronization version. This will be used the next time CHANGETABLE(CHANGES...) is called.
SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION();
-- Obtain incremental changes by using the synchronization version obtained the last time the data was synchronized.
SELECT
CT.ProductID, P.Name, P.ListPrice,
CT.SYS_CHANGE_OPERATION, CT.SYS_CHANGE_COLUMNS,
CT.SYS_CHANGE_CONTEXT
FROM
SalesLT.Product AS P
RIGHT OUTER JOIN
CHANGETABLE(CHANGES SalesLT.Product, @last_synchronization_version) AS CT
ON
P.ProductID = CT.ProductID;
Номера версий
База данных, для которой включено отслеживание изменений, содержит счетчик версий, который увеличивается при каждом изменении отслеживаемых таблиц. Каждой изменяемой строке присваивается собственный номер версии. Когда в приложение отправляется запрос изменений, вызывается функция, возвращающая номер версии. Эта функция возвращает сведения обо всех изменениях, которые были сделаны после этой версии. В некотором роде версия отслеживания изменений напоминает тип данных rowversion .
Проверка последней синхронизированной версии
Сведения об изменениях хранятся ограниченное время. Длительность времени управляется параметром CHANGE_RETENTION , который можно указать как часть ALTER DATABASE.
Указанное время CHANGE_RETENTION определяет, как часто все приложения должны запрашивать изменения из базы данных. Если приложение имеет значение старше last_synchronization_version минимальной допустимой версии синхронизации для таблицы, это приложение не может выполнить допустимое перечисление изменений. Это объясняется тем, что некоторые данные изменений могли быть удалены. Прежде чем приложение получит изменения с помощью CHANGETABLE(CHANGES ...), оно должно проверить корректность значения для last_synchronization_version, которое планирует передать в CHANGETABLE(CHANGES ...). Если значение last_synchronization_version недопустимо, это приложение должно повторно инициализировать все данные.
В следующем примере показано, как проверять достоверность значения last_synchronization_version для каждой таблицы.
-- Check individual table.
IF (@last_synchronization_version < CHANGE_TRACKING_MIN_VALID_VERSION(
OBJECT_ID('SalesLT.Product')))
BEGIN
-- Handle invalid version and do not enumerate changes.
-- Client must be reinitialized.
END;
Как показано в следующем примере, достоверность значения last_synchronization_version можно проверить для всех таблиц в базе данных.
-- Check all tables with change tracking enabled
IF EXISTS (
SELECT 1 FROM sys.change_tracking_tables
WHERE min_valid_version > @last_synchronization_version )
BEGIN
-- Handle invalid version & do not enumerate changes
-- Client must be reinitialized
END;
Использование отслеживания столбцов
Отслеживание столбцов позволяет приложениям получать изменившиеся данные не всей строки, а только одного столбца. Например, рассмотрим ситуацию, когда в таблице имеются один или два больших, но редко изменяющихся столбца и другие столбцы, значения которых часто меняются. Не применяя отслеживание столбцов, приложение может только определить изменение строки и синхронизировать все данные, включая данные больших столбцов. Но с помощью отслеживания столбцов приложение может определить, в каких столбцах изменились значения, и синхронизировать только изменившиеся данные.
Сведения об отслеживании столбцов отображаются в SYS_CHANGE_COLUMNS столбце, возвращаемом функцией CHANGETABLE(CHANGES ...) .
Отслеживание столбцов можно использовать для возврата NULL для столбца, который не изменился. Если значение столбца можно изменить на NULL, необходимо вернуть отдельный столбец, чтобы указать, был ли столбец изменен.
В следующем примере столбец будет иметь CT_ThumbnailPhoto значение, NULL если этот столбец не изменился. Этот столбец также может быть NULL, потому что он был изменен на NULL. Приложение может использовать CT_ThumbNailPhoto_Changed столбец, чтобы определить, изменен ли столбец.
DECLARE @PhotoColumnId int = COLUMNPROPERTY(
OBJECT_ID('SalesLT.Product'),'ThumbNailPhoto', 'ColumnId');
SELECT
CT.ProductID, P.Name, P.ListPrice, -- Always obtain values.
CASE
WHEN CHANGE_TRACKING_IS_COLUMN_IN_MASK(
@PhotoColumnId, CT.SYS_CHANGE_COLUMNS) = 1
THEN ThumbNailPhoto
ELSE NULL
END AS CT_ThumbNailPhoto,
CHANGE_TRACKING_IS_COLUMN_IN_MASK(
@PhotoColumnId, CT.SYS_CHANGE_COLUMNS) AS
CT_ThumbNailPhoto_Changed,
CT.SYS_CHANGE_OPERATION, CT.SYS_CHANGE_COLUMNS,
CT.SYS_CHANGE_CONTEXT
FROM
SalesLT.Product AS P
INNER JOIN
CHANGETABLE(CHANGES SalesLT.Product, @last_synchronization_version) AS CT
ON
P.ProductID = CT.ProductID AND
CT.SYS_CHANGE_OPERATION = 'U';
Получение согласованных и правильных результатов
Для получения измененных данных для таблицы требуется несколько шагов. Несогласованные или неправильные результаты могут быть возвращены, если некоторые проблемы не рассматриваются и обрабатываются.
Например, чтобы получить изменения, внесенные в таблицу Sales и SalesOrders таблицу, приложение выполнит следующие действия:
Проверьте последнюю синхронизированную версию с помощью
CHANGE_TRACKING_MIN_VALID_VERSION().Получите версию, которую можно будет использовать для внесения изменений в следующий раз с помощью
CHANGE_TRACKING_CURRENT_VERSION().Получите изменения в таблице
Salesс использованиемCHANGETABLE(CHANGES ...).Получите изменения в таблице
SalesOrdersс использованиемCHANGETABLE(CHANGES ...).
В базе данных выполняются следующие два процесса, которые могут повлиять на результаты, возвращаемые на предыдущих шагах.
Процесс очистки выполняется в фоновом режиме и удаляет данные отслеживания изменений старше указанного срока хранения.
Процесс очистки является отдельным фоновым процессом и руководствуется сроком хранения, заданным при настройке отслеживания изменений в базе данных. Проблема заключается в том, что процесс очистки может происходить в период между валидацией последней версии синхронизации и вызовом функции CHANGETABLE(CHANGES...). Последняя версия синхронизации, которая была действительна, может быть недействительна к моменту получения изменений. Поэтому функция может возвратить неверные результаты.
Текущие операции DML выполняются в таблицах Sales и
SalesOrders, например, следующие:Изменения можно вносить в таблицы после получения версии для следующего раза с помощью
CHANGE_TRACKING_CURRENT_VERSION(). Следовательно, функция может вернуть больше изменений, чем ожидалось.Транзакция может быть завершена в тот промежуток времени, который проходит между вызовом получения изменений из таблицы
Salesи вызовом получения изменений из таблицыSalesOrders. Таким образом, результаты таблицыSalesOrderмогут иметь значение внешнего ключа, которое не существует вSalesтаблице.
Для преодоления приведенных выше проблем рекомендуется применять изоляцию моментального снимка. Это позволит обеспечить согласованность сведений об изменениях и избежать соперничества при выполнении задач фоновой очистки. Если вы не используете транзакции моментальных снимков, разработка приложения, использующего отслеживание изменений, может потребовать значительно больше усилий.
Используйте изоляцию моментальных снимков
Отслеживание изменений было разработано для эффективного взаимодействия с изоляцией моментального снимка. Для базы данных необходимо включить изоляцию моментальных снимков. Все шаги, необходимые для получения изменений, должны быть включены в мгновенную транзакцию. Это гарантирует, что все изменения, внесенные в данные в процессе получения изменений, не будут видны запросам внутри транзакции моментального снимка.
Чтобы получить данные в транзакции моментального снимка, выполните следующие действия.
Установите уровень изоляции транзакции на уровень моментальных снимков и запустите транзакцию.
Проверьте последнюю версию синхронизации с помощью
CHANGE_TRACKING_MIN_VALID_VERSION().Чтобы получить используемую в следующий раз версию, примените
CHANGE_TRACKING_CURRENT_VERSION().Получение изменений для
Salesтаблицы с помощьюCHANGETABLE(CHANGES ...)Получение изменений для
SalesOrdersтаблицы с помощьюCHANGETABLE(CHANGES ...)Зафиксируйте транзакцию.
Некоторые моменты, которые следует помнить: все действия для получения изменений находятся внутри транзакции с мгновенными снимками.
Если очистка происходит после проверки последней версии синхронизации, результаты
CHANGETABLE(CHANGES ...)остаются действительными, поскольку операции удаления, выполняемые в ходе очистки, не будут видны в транзакции.Любые изменения, внесенные в таблицу
Salesили таблицуSalesOrdersпосле получения следующей версии синхронизации, не будут видны. Вызовы кCHANGETABLE(CHANGES ...)никогда не вернут изменения с версией позже, чем та, которая возвращаетсяCHANGE_TRACKING_CURRENT_VERSION(). Согласованность междуSalesтаблицей иSalesOrdersтаблицей также будет поддерживаться, так как транзакции, зафиксированные во время между вызовамиCHANGETABLE(CHANGES ...), не будут видны.
В следующем примере показано включение изоляции моментального снимка в базе данных.
-- The database must be configured to enable snapshot isolation.
ALTER DATABASE AdventureWorksLT
SET ALLOW_SNAPSHOT_ISOLATION ON;
Транзакция типа "моментальный снимок" используется следующим образом.
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRAN
-- Verify that version of the previous synchronization is valid.
-- Obtain the version to use next time.
-- Obtain changes.
COMMIT TRAN
Дополнительные сведения о транзакциях моментальных снимков см. в разделе SET TRANSACTION ISOLATION LEVEL (Transact-SQL).
Очистка и изоляция снимков
Включение изоляции моментальных снимков и отслеживания изменений в одной базе данных или в двух разных базах данных в одном экземпляре может привести к тому, что процесс очистки оставит строки sys.syscommittab с истекшим сроком действия, если в базе данных с изоляцией моментальных снимков есть открытая транзакция. Это может произойти, поскольку процесс очистки с отслеживанием изменений учитывает нижнюю конечную точку в масштабе всего экземпляра (которая является безопасной версией очистки) при выполнении очистки. Это делается для того, чтобы процесс автоматической очистки отслеживания изменений не удалял строки, которые могут понадобиться открытой транзакции в базе данных с включенной изоляцией моментального снимка. Сохраняйте транзакции уровня изоляции повторяемого чтения и изоляции моментальных снимков как можно короче, чтобы обеспечить своевременную очистку просроченных строк из sys.syscommittab.
Альтернативы изоляции мгновенных снимков
Существуют альтернативы использованию изоляции моментального снимка, но для их реализации требуется больше усилий, чтобы соответствовать всем требованиям приложений. Чтобы убедиться, что last_synchronization_version является допустимым и не удаляется процессом очистки перед получением изменений, выполните следующие действия.
Следует проверить
last_synchronization_versionпосле вызововCHANGETABLE().Проверьте
last_synchronization_versionв рамках каждого запроса, чтобы получить изменения с помощьюCHANGETABLE().
Изменения могут происходить после получения версии синхронизации для следующего перечисления. Для обхода этой ситуации существует два способа. Используемый вариант зависит от приложения и от того, как оно может справляться с побочными эффектами каждого подхода.
Пропускайте изменения с версиями больше, чем новая версия синхронизации.
Побочный эффект этого подхода заключается в том, что новая или обновленная строка будет пропущена, если она была создана или обновлена перед версией новой синхронизации, а затем обновлена после нее. Если есть новая строка, проблема целостности ссылок может возникнуть, если в другой таблице существовала строка, которая ссылалась на пропущенную строку. Если есть существующая обновленная строка, она будет пропущена и не синхронизирована до следующей попытки.
Включайте все изменения, даже с версиями, которые больше версии синхронизации.
Строки, у которых версия больше новой версии синхронизации, будут снова получены при следующей синхронизации. Приложение должно предполагать такую ситуацию и обрабатывать ее.
Кроме двух предыдущих вариантов можно разработать подход, сочетающий обе возможности в зависимости от операции. Например, может потребоваться приложение, в котором лучше игнорировать изменения, более новые, чем следующая версия синхронизации, в которой строка была создана или удалена, но обновления, при этом, не игнорируются.
Примечание.
Выбор оптимального подхода для приложения, работающего с отслеживанием изменений, или любого пользовательского средства отслеживания изменений требует тщательного анализа. Поэтому намного проще использовать изоляцию моментального снимка.
Как отслеживание изменений обрабатывает изменения в базе данных
Некоторые приложения, использующие отслеживание изменений, выполняют двустороннюю синхронизацию с другими хранилищами данных. То есть изменения, внесенные в базу данных SQL Server, обновляются в другом хранилище данных, а изменения, внесенные в другое хранилище, обновляются в базе данных SQL Server.
Если приложение обновляет локальную базу данных изменениями, сделанными в другом хранилище данных, оно должно выполнить следующие операции.
Проверить наличие конфликтов.
Конфликт возникает, когда одни и те же данные одновременно изменяются в обоих хранилищах данных. Приложение должно иметь возможность проверить наличие конфликта и получить достаточно информации для его разрешения.
Сохранить контекстные сведения приложения.
Приложение хранит данные, включающие информацию об отслеживании изменений. Эта информация должна быть доступна вместе с другими данными отслеживания изменений, если изменения были получены из локальной базы данных. Типичный пример таких контекстных сведений – идентификатор хранилища данных, которое было источником изменений.
Для выполнения вышеуказанных операций приложение синхронизации может использовать следующие функции:
CHANGETABLE(VERSION...)Когда приложение выполняет изменения, оно может использовать эту функцию для проверки конфликтов. Функция получает последние данные отслеживания изменений для заданной строки в таблице с отслеживанием изменений. Информация об отслеживании изменений включает версию строки, которая была изменена в последний раз. Это позволяет приложению определить, изменилась ли строка с момента последней синхронизации приложения.
WITH CHANGE_TRACKING_CONTEXTПриложение может использовать это предложение для хранения контекстных данных.
Проверка наличия конфликтов
В двустороннем сценарии синхронизации клиентское приложение должно определить, не была ли строка обновлена с момента последнего получения изменений приложением.
В следующем примере показано, как использовать CHANGETABLE(VERSION ...) функцию для проверки конфликтов наиболее эффективным способом без отдельного запроса. В примере CHANGETABLE(VERSION ...) определяет SYS_CHANGE_VERSION для строки, заданной аргументом @product id.
CHANGETABLE(CHANGES ...) может получить те же сведения, но это будет менее эффективным. Если значение SYS_CHANGE_VERSION строки больше значения @last_sync_version, возникает конфликт. Если возникает конфликт, строка не будет обновлена. Проверка ISNULL() необходима, поскольку для строки может не иметься информации об изменениях. Информация об изменении отсутствовала бы, если строка не была обновлена с момента включения отслеживания изменений или с момента очистки информации об изменениях.
-- Assumption: @last_sync_version has been validated.
UPDATE SalesLT.Product
SET ListPrice = @new_listprice
FROM SalesLT.Product AS P
WHERE ProductID = @product_id
AND @last_sync_version >= ISNULL((
SELECT CT.SYS_CHANGE_VERSION
FROM CHANGETABLE(VERSION SalesLT.Product, (ProductID), (P.ProductID)) AS CT
), 0);
Следующий код проверяет обновленное число строк и может предоставить более подробные сведения о конфликте.
-- If the change cannot be made, find out more information.
IF (@@ROWCOUNT = 0)
BEGIN
-- Obtain the complete change information for the row.
SELECT
CT.SYS_CHANGE_VERSION, CT.SYS_CHANGE_CREATION_VERSION,
CT.SYS_CHANGE_OPERATION, CT.SYS_CHANGE_COLUMNS
FROM
CHANGETABLE(CHANGES SalesLT.Product, @last_sync_version) AS CT
WHERE
CT.ProductID = @product_id;
-- Check CT.SYS_CHANGE_VERSION to verify that it really was a conflict.
-- Check CT.SYS_CHANGE_OPERATION to determine the type of conflict:
-- update-update or update-delete.
-- The row that is specified by @product_id might no longer exist
-- if it has been deleted.
END
Настройка сведений о контексте
Используя WITH CHANGE_TRACKING_CONTEXT предложение, приложение может хранить сведения о контексте вместе с информацией об изменении. Затем эти сведения можно получить из столбца, возвращаемого SYS_CHANGE_CONTEXTCHANGETABLE(CHANGES ...).
Контекстные данные обычно используются для определения источника изменений. Если источник изменений можно определить, эти данные могут использоваться хранилищем данных, чтобы не получать изменения при повторной синхронизации.
-- Try to update the row and check for a conflict.
WITH CHANGE_TRACKING_CONTEXT (@source_id)
UPDATE
SalesLT.Product
SET
ListPrice = @new_listprice
FROM
SalesLT.Product AS P
WHERE
ProductID = @product_id AND
@last_sync_version >= ISNULL (
(SELECT CT.SYS_CHANGE_VERSION FROM CHANGETABLE(VERSION SalesLT.Product,
(ProductID), (P.ProductID)) AS CT),
0);
Обеспечение согласованности и правильности результатов
Приложение должно учитывать процесс очистки при проверке значения параметра @last_sync_version. Это связано с тем, что данные могли быть удалены после CHANGE_TRACKING_MIN_VALID_VERSION() вызова, но до обновления.
Следует использовать изоляцию мгновенных снимков и вносить изменения в рамках транзакции с использованием мгновенных снимков.
-- Prerequisite is to ensure ALLOW_SNAPSHOT_ISOLATION is ON for the database.
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRAN
-- Verify that last_sync_version is valid.
IF (@last_sync_version <
CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('SalesLT.Product')))
BEGIN
RAISERROR (N'Last_sync_version too old', 16, -1);
END
ELSE
BEGIN
-- Try to update the row.
-- Check @@ROWCOUNT and check for a conflict.
END;
COMMIT TRAN;
Примечание.
Существует вероятность того, что обновляемая в рамках транзакции моментальных снимков строка уже была обновлена в другой транзакции после начала транзакции моментальных снимков. В этом случае произойдет конфликт обновления при изоляции снапшотов, который приведет к завершению транзакции. В этом случае повторите попытку обновления. В дальнейшем это приведет к обнаружению конфликта отслеживания изменений, и ни одна из строк не будет обновлена.
Отслеживание изменений и восстановление данных
Приложения, для которых необходима синхронизация, должны учитывать возможность восстановления базы данных, для которой включено отслеживание изменений, в предыдущее состояние. Это может произойти после восстановления базы данных из резервной копии, при переключении на асинхронное зеркальное отображение базы данных или при сбое при использовании доставки журналов. Эту проблему иллюстрирует следующий сценарий.
Таблица T1 отслеживает внесенные изменения, а минимально допустимая версия таблицы — 50.
Клиентское приложение синхронизирует данные на версии 100 и получает информацию о всех изменениях между версиями 50 и 100.
После версии 100 в таблицу Т1 были внесены дополнительные изменения.
В версии 120 возникает сбой, а администратор базы данных восстанавливает базу данных с потерей данных. После завершения восстановления таблица содержит данные до версии 70, а минимальная синхронизированная версия по-прежнему равна 50.
Это означает, что синхронизированное хранилище данных содержит данные, которых уже нет в первичном хранилище.
Таблица Т1 обновлялась многократно. Это довело текущую версию до 130.
Клиентское приложение снова синхронизируется и передает последний синхронизированный номер 100. Проверка этого номера клиентом происходит успешно, так как 100 больше 50.
Клиент получает изменения между версиями 100 и 130. На этом этапе клиент не знает, что изменения в диапазоне от 70 до 100 не совпадают с ранее. Данные на клиенте и сервере не синхронизируются.
Если база данных была восстановлена до точки после версии 100, не будет проблем с синхронизацией. Клиент и сервер должны правильно синхронизировать данные во время следующего интервала синхронизации.
Отслеживание изменений не обеспечивает поддержку восстановления после потери данных. Однако существует две возможности обнаружения проблем синхронизации такого рода.
Сохраните идентификатор версии базы данных на сервере и обновляйте это значение при каждом восстановлении данных или их потере, вызванной любыми другими причинами. Этот идентификатор должно хранить и проверять во время синхронизации данных каждое клиентское приложение. Если возникает потеря данных, идентификаторы не будут совпадать, и клиенты будут повторно инициализироваться. Один из недостатков заключается в том, что если потеря данных не пересекла последнюю синхронизированную границу, клиент может сделать ненужную повторную инициализацию.
Когда клиент делает запрос об изменениях, сохраните номер последней версии синхронизации каждого клиента сервера. Если возникла проблема с данными, последние синхронизированные номера версий не совпадут. Это будет означать, что необходима повторная инициализация.
Связанный контент
- Отслеживание изменений данных (SQL Server)
- Сведения об отслеживании изменений (SQL Server)
- Управление отслеживанием изменений (SQL Server)
- Включение и отключение отслеживания изменений (SQL Server)
- CHANGETABLE (Transact-SQL)
- CHANGE_TRACKING_MIN_VALID_VERSION (Transact-SQL)
- ТЕКУЩАЯ_ВЕРСИЯ_ОТСЛЕЖИВАНИЯ_ИЗМЕНЕНИЙ (Transact-SQL)
- С ИСПОЛЬЗОВАНИЕМ CHANGE_TRACKING_CONTEXT (Transact-SQL)