Работа с отслеживанием изменений (SQL Server)Work with Change Tracking (SQL Server)

ОБЛАСТЬ ПРИМЕНЕНИЯ: даSQL Server даБаза данных SQL AzureнетХранилище данных SQL AzureнетParallel Data WarehouseAPPLIES TO: yesSQL Server yesAzure SQL Database noAzure SQL Data Warehouse noParallel Data Warehouse

Приложения, в которых используется отслеживание изменений, должны иметь возможность получать отслеженные изменения, применять эти изменения к другому хранилищу данных и обновлять базу данных-источник.Applications that use change tracking must be able to obtain tracked changes, apply these changes to another data store, and update the source database. В этом разделе описаны способы выполнения этих задач и роль отслеживания изменений в случае отработки отказа и необходимостью восстановить базу данных из резервной копии.This topic describes how to perform these tasks, and also the role change tracking plays when a failover occurs and a database must be restored from a backup.

Получение изменений с помощью функций отслеживания измененийObtain Changes by Using Change Tracking Functions

Описывает, как использовать функции отслеживания изменений, чтобы получить изменения и сведения об изменениях, произведенных в базе данных.Describes how to use the change tracking functions to obtain changes and information about the changes that were made to a database.

Сведения о функциях отслеживания измененийAbout the Change Tracking Functions

Чтобы получить изменения из базы данных и сведения об этих изменениях, приложения могут использовать следующие функции.Applications can use the following functions to obtain the changes that are made in a database and information about the changes:

Функция CHANGETABLE(CHANGES ...)CHANGETABLE(CHANGES ...) function
Эта функция, возвращающая набор строк, используется в запросе данных отслеживания изменений.This rowset function is used to query for change information. Функция запрашивает данные, хранящиеся во внутренних таблицах отслеживания изменений.The function queries the data stored in the internal change tracking tables. Она возвращает результирующий набор, содержащий первичные ключи измененных строк, а также другие сведения: операцию, число обновленных столбцов и версии строк.The function returns a results set that contains the primary keys of rows that have changed together with other change information such as the operation, columns updated and version for the row.

Функция CHANGETABLE(CHANGES ...) получает в качестве аргумента последнюю версию синхронизации.CHANGETABLE(CHANGES ...) takes a last synchronization version as an argument. Версию, установленную при последней синхронизации, можно получить из переменной @last_synchronization_version .The last sychronization version is obtained using the @last_synchronization_version variable. Семантика последней версии синхронизации выглядит следующим образом.The semantics of the last synchronization version are as follows:

  • Вызывающий клиент получает сведения обо всех изменениях, происшедших до момента последней синхронизированной версии включительно.The calling client has obtained changes and knows about all changes up to and including the last synchronization version.

  • Функция CHANGETABLE(CHANGES ...) поэтому возвращает сведения обо всех изменениях, произошедших после последней версии синхронизации.CHANGETABLE(CHANGES ...) will therefore return all changes that have occurred after the last synchronization version.

    Ниже показано, как функция CHANGETABLE(CHANGES ...) используется для получения изменений.The following illustration shows how CHANGETABLE(CHANGES ...) is used to obtain changes.

    Пример выходных данных запроса на отслеживание измененийExample of change tracking query output

Функция CHANGE_TRACKING_CURRENT_VERSION()CHANGE_TRACKING_CURRENT_VERSION() function
Используется для получения текущей версии, которая будет применяться при следующем запросе изменений.Is used to obtain the current version that will be used the next time when querying changes. Эта версия представляет версию последней зафиксированной транзакции.This version represents the version of the last committed transaction.

Функция CHANGE_TRACKING_MIN_VALID_VERSION()CHANGE_TRACKING_MIN_VALID_VERSION() function
Используется для получения минимальной допустимой версии, имеющейся у клиента, при которой он еще сможет получать достоверные результаты из функции CHANGETABLE().Is used to obtain the minimum valid version that a client can have and still obtain valid results from CHANGETABLE(). Клиент должен сравнить последнюю версию синхронизации со значением, возвращенным этой функцией.The client should check the last synchronization version against the value thatis returned by this function. Если номер последней версии синхронизации меньше, чем возвращает эта функция, то он не сможет получить достоверные результаты из функции CHANGETABLE() и должен повторно инициализировать данные.If the last synchronization version is less than the version returned by this function, the client will be unable to obtain valid results from CHANGETABLE() and will have to reinitialize.

Получение первоначальных данныхObtaining Initial Data

Прежде чем приложение в первый раз получит изменения, оно должно выполнить запрос для получения первоначальных данных и версии синхронизации.Before an application can obtain changes for the first time, the application must send a query to obtain the initial data and the synchronization version. Приложение должно получить соответствующие данные напрямую из таблицы, а затем вызвать функцию CHANGE_TRACKING_CURRENT_VERSION() для получения первоначальной версии.The application must obtain the appropriate data directly from the table, and then use CHANGE_TRACKING_CURRENT_VERSION() to obtain the initial version. Эта версия передается функции CHANGETABLE(CHANGES ...) при первом получении изменений.This version will be passed to CHANGETABLE(CHANGES ...) the first time that changes are obtained.

В следующем примере показано получение первоначальной версии синхронизации и первоначального набора данных.The following example shows how to obtain the initial synchronization version and the initial data set.

    -- 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  

Использование функций отслеживания изменений для получения измененийUsing the Change Tracking Functions to Obtain Changes

Чтобы получить измененные строки таблицы и сведения об этих изменениях, используется функция CHANGETABLE(CHANGES...). Например, следующий запрос получает изменения в таблице SalesLT.Product .To obtain the changed rows for a table and information about the changes, use CHANGETABLE(CHANGES...). For example, the following query obtains changes for the SalesLT.Product table.

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  
  

Как правило, клиенту нужно получить последние данные строки, а не просто первичные ключи.Usually, a client will want to obtain the latest data for a row instead of only the primary keys for the row. Поэтому приложение соединяет результаты запроса функции CHANGETABLE(CHANGES ...) с данными в пользовательской таблице.Therefore, an application would join the results from CHANGETABLE(CHANGES ...) with the data in the user table. Например, следующий запрос соединяется с таблицей SalesLT.Product , чтобы получить значения столбцов Name и ListPrice .For example, the following query joins with the SalesLT.Product table to obtain the values for the Name and ListPrice columns. Обратите внимание на использование OUTER JOIN.Note the use of OUTER JOIN. Это требуется, чтобы убедиться, что возвращаются сведения об изменениях в строках, удаленных из пользовательской таблицы.This is required to make sure that the change information is returned for those rows that have been deleted from the user table.

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(), как показано в следующем примере.To obtain the version for use in the next change enumeration, use CHANGE_TRACKING_CURRENT_VERSION(), as shown in the following example.

SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION()  

Когда приложение получает изменения, оно должно использовать как функцию CHANGETABLE(CHANGES...), так и CHANGE_TRACKING_CURRENT_VERSION(), как показано в следующем примере.When an application obtains changes, it must use both CHANGETABLE(CHANGES...) and CHANGE_TRACKING_CURRENT_VERSION(), as shown in the following example.

-- 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  

Номера версийVersion Numbers

База данных, для которой включено отслеживание изменений, содержит счетчик версий, который увеличивается при каждом изменении отслеживаемых таблиц.A database that has change tracking enabled has a version counter that increases as changes are made to change tracked tables. Каждой изменяемой строке присваивается собственный номер версии.Each changed row has a version number that is associated with it. Когда в приложение отправляется запрос изменений, вызывается функция, возвращающая номер версии.When a request is sent to an application to query for changes, a function is called that supplies a version number. Эта функция возвращает сведения обо всех изменениях, которые были сделаны после этой версии.The function returns information about all the changes that have been made since that version. В некотором роде версия отслеживания изменений напоминает тип данных rowversion .In some ways, change tracking version is similar in concept to the rowversion data type.

Проверка последней синхронизированной версииValidating the Last Synchronized Version

Сведения об изменениях хранятся ограниченное время.Information about changes is maintained for a limited time. Длительность этого времени управляется параметром CHANGE_RETENTION, который указывается в инструкции ALTER DATABASE.The length of time is controlled by the CHANGE_RETENTION parameter that can be specified as part of the ALTER DATABASE.

Имейте в виду, что время, заданное параметром CHANGE_RETENTION, определяет, как часто все приложения должны запрашивать изменения в базе данных.Be aware that the time specified for CHANGE_RETENTION determines how frequently all applications must request changes from the database. Если значение параметра last_synchronization_version в приложении старше минимально допустимой версии синхронизации для таблицы, это приложение не сможет выполнить достоверное перечисление изменений.If an application has a value for last_synchronization_version that is older than the minimum valid synchronization version for a table, that application cannot perform valid change enumeration. Это объясняется тем, что некоторые данные изменений могли быть очищены.This is because some change information might have been cleaned up. Прежде чем приложение получит изменения с помощью функции CHANGETABLE(CHANGES ...), оно должно проверить значение параметра last_synchronization_version , которое нужно передать функции CHANGETABLE(CHANGES ...). Если значение параметра last_synchronization_version недопустимо, приложение должно повторно инициализировать все данные.Before an application obtains changes by using CHANGETABLE(CHANGES ...), the application must validate the value for last_synchronization_version that it plans to pass to CHANGETABLE(CHANGES ...). If the value of last_synchronization_version is not valid, that application must reinitialize all the data.

В следующем примере показано, как проверять достоверность значения last_synchronization_version для каждой таблицы.The following example shows how to verify the validity of the value of last_synchronization_version for each table.

-- 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 можно проверить для всех таблиц в базе данных.As the following example shows, the validity of the value of last_synchronization_version can be checked against all tables in the database.

-- Check all tables with change tracking enabled  
IF EXISTS (  
  SELECT COUNT(*) 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  

Использование отслеживания столбцовUsing Column Tracking

Отслеживание столбцов позволяет приложениям получать изменившиеся данные не всей строки, а только одного столбца.Column tracking enables applications to obtain the data for only the columns that have changed instead of the whole row. Например, рассмотрим ситуацию, когда в таблице имеются один или два больших, но редко изменяющихся столбца и другие столбцы, значения которых часто меняются.For example, consider the scenario in which a table has one or more columns that are large, but rarely change; and also has other columns that frequently change. Не применяя отслеживание столбцов, приложение может только определить изменение строки и синхронизировать все данные, включая данные больших столбцов.Without column tracking, an application can only determine that a row has changed and would have to synchronize all the data that includes the large column data. Но с помощью отслеживания столбцов приложение может определить, в каких столбцах изменились значения, и синхронизировать только изменившиеся данные.However, by using column tracking, an application can determine whether the large column data changed and only synchronize the data if it has changed.

Сведения об отслеживании столбцов отображаются в столбце SYS_CHANGE_COLUMNS, который возвращается функцией CHANGETABLE(CHANGES ...).Column tracking information appears in the SYS_CHANGE_COLUMNS column that is returned by the CHANGETABLE(CHANGES ...) function.

Отслеживание столбцов может применяться таким образом, чтобы для всех неизменившихся столбцов возвращалось значение NULL.Column tracking can be used so that NULL is returned for a column that has not changed. Если значение NULL недопустимо для того или иного столбца, можно возвратить отдельный столбец, который укажет, изменялись ли данные этого столбца.If the column can be changed to NULL, a separate column must be returned to indicate whether the column changed.

В следующем примере столбец CT_ThumbnailPhoto будет иметь значение NULL , если он не был изменен.In the following example, the CT_ThumbnailPhoto column will be NULL if that column did not change. Этот столбец может также принимать значение NULL , потому что он был изменен на NULL , поэтому приложение может использовать столбец CT_ThumbNailPhoto_Changed , чтобы определить, происходили ли изменения.This column could also be NULL because it was changed to NULL - the application can use the CT_ThumbNailPhoto_Changed column to determine whether the column 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'  

Получение согласованных и правильных результатовObtaining Consistent and Correct Results

Для получения измененных данных для таблицы требуется несколько шагов.Obtaining the changed data for a table requires multiple steps. Имейте в виду, что, если не удастся решить некоторые проблемы, будут возвращены несогласованные или неверные результаты.Be aware that inconsistent or incorrect results could be returned if certain issues are not considered and handled.

Например, чтобы получить изменения в таблицах Sales и SalesOrders, приложение должно выполнить следующие действия.For example, to obtain the changes that were made to a Sales table and SalesOrders table, an application would perform the following steps:

  1. Проверить последнюю синхронизированную версию с помощью функции CHANGE_TRACKING_MIN_VALID_VERSION().Validate the last synchronized version by using CHANGE_TRACKING_MIN_VALID_VERSION().

  2. Получить версию, которая будет использована для получения изменений в следующий раз, с помощью функции CHANGE_TRACKING_CURRENT_VERSION().Obtain the version that can be used to obtain change the next time by using CHANGE_TRACKING_CURRENT_VERSION().

  3. Получите изменения для таблицы Sales с помощью функции CHANGETABLE(CHANGES ...).Obtain the changes for the Sales table by using CHANGETABLE(CHANGES ...).

  4. Получите изменения для таблицы SalesOrders с помощью функции CHANGETABLE(CHANGES ...).Obtain the changes for the SalesOrders table by using CHANGETABLE(CHANGES ...).

Мы слушаем! Если вы обнаружили в этой статье устаревшие или недостоверные сведения, например инструкции или пример кода, сообщите нам.We are listening: If you find something outdated or incorrect in this article, such as a step or a code example, please tell us. Можно воспользоваться кнопкой Эта страница в разделе Отзывы внизу страницы.You can click the This page button in the Feedback section at the bottom of this page. Обычно мы читаем отзывы про материалы по SQL на следующий день.We read every item of feedback about SQL, typically the next day. Благодарим вас.Thanks.

В базе данных выполняются следующие два процесса, которые могут повлиять на результаты, возвращаемые на предыдущих шагах.Two processes are occurring in the database that can affect the results that are returned by the previous steps:

  • Процесс очистки выполняется в фоновом режиме и удаляет данные отслеживания изменений старше указанного срока хранения.The cleanup process runs in the background and removes change tracking information that is older than the specified retention period.

    Процесс очистки является отдельным фоновым процессом и руководствуется сроком хранения, заданным при настройке отслеживания изменений в базе данных.The cleanup process is a separate background process that uses the retention period that is specified when you configure change tracking for the database. Проблема заключается в том, что он может выполняться в промежуток между проверкой последней версии синхронизации и вызовом функции CHANGETABLE(CHANGES...).The issue is that the cleanup process can occur in the time between when the last synchronization version was validated and when the call to CHANGETABLE(CHANGES...) is made. Последняя достоверная версия синхронизации может оказаться ошибочной ко времени получения изменений.A last synchronization version that was just valid might no longer be valid by the time the changes are obtained. Поэтому функция может возвратить неверные результаты.Therefore, incorrect results might be returned.

  • В таблицах Sales и SalesOrders постоянно выполняются операции DML, например следующие.Ongoing DML operations are occurring in the Sales and SalesOrders tables, such as the following operations:

    • В таблицах могут происходить изменения после того, как с помощью функции CHANGE_TRACKING_CURRENT_VERSION() была получена последняя версия синхронизации.Changes can be made to the tables after the version for next time has been obtained by using CHANGE_TRACKING_CURRENT_VERSION(). Следовательно, функция может вернуть больше изменений, чем ожидалось.Therefore, more changes can be returned than expected.

    • Между вызовами функций для получения изменений из таблицы Sales и из таблицы SalesOrders могут быть зафиксированы транзакции.A transaction could commit in the time between the call to obtain changes from the Sales table and the call to obtain changes from the SalesOrders table. Следовательно, результаты для таблицы SalesOrder могут содержать внешние ключи, не имеющиеся в таблице Sales.Therefore, the results for the SalesOrder table could have foreign key value that does not exist in the Sales table.

Для преодоления приведенных выше проблем рекомендуется применять изоляцию моментального снимка.To overcome the previously listed challenges, we recommend that you use snapshot isolation. Это позволит обеспечить согласованность сведений об изменениях и избежать соперничества при выполнении задач фоновой очистки.This will help to ensure consistency of change information and avoid race conditions that are related to the background cleanup task. Если не применять транзакции моментального снимка, разработка приложения, использующего отслеживание изменений, может потребовать значительно больше усилий.If you do not use snapshot transactions, developing an application that uses change tracking could require significantly more effort.

Использование изоляции моментального снимкаUsing Snapshot Isolation

Отслеживание изменений было разработано для слаженной работы вместе с изоляцией моментального снимка.Change tracking has been designed to work well with snapshot isolation. В базе данных необходимо активировать изоляцию моментального снимка.Snapshot isolation must be enabled for the database. Все шаги, необходимые для получения изменений, должны включаться в транзакцию моментального снимка.All the steps that are required to obtain changes must be included inside a snapshot transaction. Этим обеспечивается то, что все изменения данных, выполненные во время получения изменений, не будут видны запросам внутри транзакции моментального снимка.This will ensure that all changes that are made to data while obtaining changes will not be visible to the queries inside the snapshot transaction.

Чтобы получить данные в транзакции моментального снимка, выполните следующие действия.To obtain data inside a snapshot transaction, perform the following steps:

  1. Установите уровень изоляции транзакции на уровень моментальных снимков и запустите транзакцию.Set the transaction isolation level to snapshot and start a transaction.

  2. Проверьте последнюю версию синхронизации с помощью функции CHANGE_TRACKING_MIN_VALID_VERSION().Validate the last synchronization version by using CHANGE_TRACKING_MIN_VALID_VERSION().

  3. Получите версию, которая будет использоваться в следующий раз, с помощью функции CHANGE_TRACKING_CURRENT_VERSION().Obtain the version to be used the next time by using CHANGE_TRACKING_CURRENT_VERSION().

  4. Получите изменения для таблицы Sales с помощью функции CHANGETABLE(CHANGES ...).Obtain the changes for the Sales table by using CHANGETABLE(CHANGES ...)

  5. Получите изменения для таблицы SalesOrders с помощью функции CHANGETABLE(CHANGES ...).Obtain the changes for the Salesorders table by using CHANGETABLE(CHANGES ...)

  6. Зафиксируйте транзакцию.Commit the transaction.

Необходимо помнить, что все действия для получения изменений находятся внутри транзакции моментальных снимков.Some points to remember as all steps to obtain changes are inside a snapshot transaction:

  • Если очистка происходит после проверки последней версии синхронизации, результаты функции CHANGETABLE(CHANGES ...) будут, тем не менее, достоверными, так как операция удаления, выполняемая процессом очистки, не будет видна внутри транзакции.If cleanup occurs after the last synchronization version is validated, the results from CHANGETABLE(CHANGES ...) will still be valid as the delete operations performed by cleanup will not be visible inside the transaction.

  • Все изменения в таблице Sales или SalesOrders после получения версии следующей синхронизации не будут видны в транзакции, поэтому вызовы функции CHANGETABLE(CHANGES ...) никогда не будут возвращать изменения с версией более поздней, чем возвращенные функцией CHANGE_TRACKING_CURRENT_VERSION().Any changes that are made to the Sales table or the SalesOrders table after the next synchronization version is obtained will not be visible, and the calls to CHANGETABLE(CHANGES ...) will never return changes with a version later than that returned by CHANGE_TRACKING_CURRENT_VERSION(). Сохранится также согласованность между таблицами Sales и SalesOrders, поскольку транзакции, зафиксированные между вызовами функции CHANGETABLE(CHANGES ...), будут невидимы.Consistency between the Sales table and the SalesOrders table will also be maintained, because the transactions that were committed in the time between calls to CHANGETABLE(CHANGES ...) will not be visible.

В следующем примере показано включение изоляции моментального снимка в базе данных.The following example shows how snapshot isolation is enabled for a database.

-- The database must be configured to enable snapshot isolation.  
ALTER DATABASE AdventureWorksLT  
    SET ALLOW_SNAPSHOT_ISOLATION ON;  

Транзакция моментального снимка используется следующим образом.A snapshot transaction is used as follows:

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).For more information about snapshot transactions, see SET TRANSACTION ISOLATION LEVEL (Transact-SQL).

Альтернативы для изоляции моментального снимкаAlternatives to Using Snapshot Isolation

Существуют альтернативы использованию изоляции моментального снимка, но они требуют больше усилий, чтобы обеспечить требования всех приложений.There are alternatives to using snapshot isolation, but they require more work to make sure all application requirements are met. Чтобы убедиться в достоверности параметра last_synchronization_version , а также в том, что данные не удаляются процессом очистки до получения изменений, выполните следующие действия.To make sure the last_synchronization_version is valid and data is not removed by the cleanup process before changes are obtained, do the following:

  1. Проверьте параметр last_synchronization_version после вызовов функции CHANGETABLE().Check last_synchronization_version after the calls to CHANGETABLE().

  2. Проверяйте параметр last_synchronization_version в составе каждого запроса, чтобы получить изменения с помощью функции CHANGETABLE().Check last_synchronization_version as part of each query to obtain changes by using CHANGETABLE().

Изменения могут происходить после получения версии синхронизации для следующего перечисления.Changes can occur after the synchronization version for the next enumeration has been obtained. Для обхода этой ситуации существует два способа.There are two ways to handle this situation. Используемый вариант зависит от приложения и обработки побочных эффектов каждого подхода.The option that is used depends on the application and how it can handle the side-effects of each approach:

  • Пропускайте изменения с версиями больше, чем новая версия синхронизации.Ignore changes that have a version larger than the new synchronization version.

    Побочный эффект этого подхода заключается в том, что новая или обновленная строка будет пропущена, если она была создана или обновлена перед версией новой синхронизации, а затем обновлена после нее.This approach has the side effect that a new or updated row would be skipped if it was created or updated before the new synchronization version, but then updated afterward. Если имеется новая строка, может возникнуть нарушение ссылочной целостности, если в другой таблице была создана строка, которая ссылалась на пропущенную строку.If there is a new row, a referential integrity problem might occur if there was a row in another table that was created that referenced the skipped row. Если существует обновленная строка, она будет пропущена и не синхронизирована до следующего раза.If there is an updated existing row, the row will be skipped and not synchronized until the next time.

  • Включайте все изменения, даже с версиями больше, чем версия новой синхронизации.Include all changes, even those that have a version larger than the new synchronization version.

    Строки с версиями больше, чем версия новой синхронизации, будут опять получены во время следующей синхронизации.The rows that have a version larger than the new synchronization version will be obtained again on the next synchronization. Приложение должно предполагать такую ситуацию и обрабатывать ее.This must be expected and handled by the application.

Кроме двух предыдущих вариантов можно разработать подход, сочетающий обе возможности в зависимости от операции.In addition to the previous two options, you can devise approach that combines both options, depending on the operation. Например, приложение может пропустить более новые изменения, чем версия следующей синхронизации, в том что касается создания или удаления, но не игнорировать обновления.For example, you might want an application for which it is best to ignore changes newer than the next synchronization version in which the row was created or deleted, but updates are not ignored.

Примечание

Выбор оптимального подхода для приложения, работающего с отслеживанием изменений, или любого пользовательского средства отслеживания изменений требует тщательного анализа.Choosing the approach that will work for the application when you are using change tracking (or any custom tracking mechanism), requires significant analysis. Поэтому намного проще использовать изоляцию моментального снимка.Therefore, it is much simpler to use snapshot isolation.

Как система отслеживания изменений обрабатывает изменения в базе данныхHow Change Tracking Handles Changes to a Database

Некоторые приложения, использующие отслеживание изменений, выполняют двустороннюю синхронизацию с другими хранилищами данных.Some applications that use change tracking perform two-way synchronization with another data store. Это означает, что изменения в базе данных SQL ServerSQL Server обновляются в другом хранилище данных, а изменения в другом хранилище данных обновляются в базе данных SQL ServerSQL Server .That is, changes that are made in the SQL ServerSQL Server database are updated in the other data store, and changes that are made in the other store are updated in the SQL ServerSQL Server database.

Если приложение обновляет локальную базу данных изменениями, сделанными в другом хранилище данных, оно должно выполнить следующие операции.When an application updates the local database with changes from another data store, the application must perform the following operations:

  • Проверить наличие конфликтов.Check for conflicts.

    Конфликт возникает, когда одни и те же данные одновременно изменяются в обоих хранилищах данных.A conflict occurs when the same data is changed at the same time in both data stores. Приложение должно иметь возможность проверить наличие конфликта и получить достаточно информации для его разрешения.The application must be able to check for a conflict and obtain enough information to enable the conflict to be resolved.

  • Сохранить контекстные сведения приложения.Store application context information.

    Приложение хранит данные, с которыми связана информация отслеживания изменений.The application stores data that has the change tracking information. Эта информация должна быть доступна вместе с другими данными отслеживания изменений, если изменения были получены из локальной базы данных.This information would be available together with other change tracking information when changes were obtained from the local database. Типичный пример таких контекстных сведений – идентификатор хранилища данных, которое было источником изменений.A common example of this contextual information is an identifier for the data store that was the source of the change.

Для выполнения вышеуказанных операций приложение синхронизации может использовать следующие функции:To perform the previous operations, a synchronization application can use the following functions:

  • CHANGETABLE(VERSION...)CHANGETABLE(VERSION...)

    Когда приложение выполняет изменения, оно может использовать эту функцию для проверки конфликтов.When an application is making changes, it can use this function to check for conflicts. Функция получает последние данные отслеживания изменений в заданной строке в таблицу отслеживания изменений.The function obtains the latest change tracking information for a specified row in a change tracked table. Эти данные содержат версию последней измененной строки.The change tracking information includes the version of the row that was last changed. Это позволяет приложению определить, изменилась ли строка с момента последней синхронизации приложения.This information enables an application to determine whether the row was changed after the last time that the application was synchronized.

  • WITH CHANGE_TRACKING_CONTEXTWITH CHANGE_TRACKING_CONTEXT

    Приложение может использовать это предложение для хранения контекстных данных.An application can use this clause to store context data.

Проверка наличия конфликтовChecking for Conflicts

В сценарии двусторонней синхронизации клиентское приложение должно определить, обновлялась ли строка с момента получения приложением последних изменений.In a two-way synchronization scenario, the client application must determine whether a row has not been updated since the application last obtained the changes.

В следующем примере показано использование функции CHANGETABLE(VERSION ...) для проверки конфликтов самым эффективным способом — без отдельного запроса.The following example shows how to use the CHANGETABLE(VERSION ...) function to check for conflicts in the most efficient way, without a separate query. В примере CHANGETABLE(VERSION ...) определяет SYS_CHANGE_VERSION для строки, заданной аргументом @product id.In the example, CHANGETABLE(VERSION ...) determines the SYS_CHANGE_VERSION for the row specified by @product id. CHANGETABLE(CHANGES ...) может получить те же сведения, но это будет менее эффективным.CHANGETABLE(CHANGES ...) can obtain the same information, but that would be less efficient. Если значение SYS_CHANGE_VERSION для строки больше, чем значение @last_sync_version, существует конфликт.If the value of SYS_CHANGE_VERSION for the row is larger than the value of @last_sync_version, there is a conflict. Если возникает конфликт, эта строка не будет обновляться.If there is a conflict, the row will not be updated. Проверка ISNULL() необходима, поскольку для строки может не иметься информации об изменениях.The ISNULL() check is required because there might be no change information available for the row. Информации об изменениях не будет, если строка не была обновлена со времени включения отслеживания изменений или времени очистки информации об изменениях.No change information would exist if the row had not been updated since change tracking was enabled or since the change information was cleaned up.

-- 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)  

Следующий код проверяет обновленное число строк и может предоставить более подробные сведения о конфликте.The following code can check the updated row count and can identify more information about the conflict.

-- 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  

Установка контекстных данныхSetting Context Information

С помощью предложения WITH CHANGE_TRACKING_CONTEXT приложение может хранить контекстные данные вместе с информацией об изменениях.By using the WITH CHANGE_TRACKING_CONTEXT clause, an application can store context information together with the change information. Затем эти данные можно получить в столбце SYS_CHANGE_CONTEXT, который возвращает функция CHANGETABLE(CHANGES ...).This information can then be obtained from the SYS_CHANGE_CONTEXT column that is returned by CHANGETABLE(CHANGES ...).

Контекстные данные обычно используются для определения источника изменений.Context information is typically used to identify the source of the changes. Если источник изменений можно определить, эти данные могут использоваться хранилищем данных, чтобы не получать изменения при повторной синхронизации.If the source of the change can be identified, that information can be used by a data store to avoid obtaining changes when it synchronizes again.

  -- 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)  

Обеспечение согласованных и правильных результатовEnsuring Consistent and Correct Results

Приложение должно учитывать процесс очистки при проверке значения параметра @last_sync_version.An application must consider the cleanup process when it validates the value of @last_sync_version. Это объясняется тем, что данные могли быть удалены после вызова функции CHANGE_TRACKING_MIN_VALID_VERSION(), но перед тем, как было выполнено обновление.This is because data could have been removed after CHANGE_TRACKING_MIN_VALID_VERSION() was called, but before the update was made.

Важно!

Рекомендуется использовать изоляцию моментального снимка и выполнять изменения в транзакции моментального снимка.We recommend that you use snapshot isolation and make the changes within a snapshot transaction.

-- 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  

Примечание

Существует вероятность того, что обновляемая в рамках транзакции моментальных снимков строка уже была обновлена в другой транзакции после начала транзакции моментальных снимков.There is a possibility that the row being updated within the snapshot transaction could have been updated in another transaction after the snapshot transaction was started. В этом случае произойдет конфликт обновления при изоляции моментальных снимков, который вызовет прекращение транзакции.In this case, a snapshot isolation update conflict will occur and lead to the transaction being terminated. В этом случае повторите попытку обновления.If this happens, retry the update. В дальнейшем это приведет к обнаружению конфликта отслеживания изменений и ни одна из строк обновлена не будет.This will then lead to a change tracking conflict being detected and no rows being changed.

Изменение отслеживания и восстановление данныхChange Tracking and Data Restore

Приложения, для которых необходима синхронизация, должны учитывать возможность восстановления базы данных, для которой включено отслеживание изменений, в предыдущее состояние.Applications that require synchronization must consider the case in which a database that has change tracking enabled reverts to an earlier version of the data. Речь идет о восстановлении базы данных из резервной копии при отработке отказа на асинхронную зеркальную базу данных или сбое при доставке журналов.This can occur after a database is restored from a backup, when there is a failover to an asynchronous database mirror, or when there is a failure when using log shipping. Эту проблему иллюстрирует следующий сценарий.The following scenario illustrates the issue:

  1. Для таблицы Т1 включено отслеживание изменений. Минимальный действительный номер версии равен 50.Table T1 is change tracked, and the minimum valid version for table is 50.

  2. Клиентское приложение синхронизирует данные версии 100 и получает все данные отслеживания изменений, произведенных с версии 50 до версии 100.A client application synchronizes data at version 100 and obtains information about all changes between versions 50 and 100.

  3. После версии 100 в таблицу Т1 были внесены дополнительные изменения.Additional changes are made to table T1 after version 100.

  4. После создания версии 120 произошел сбой, и участник базы данных восстанавливает базу с потерей части данных.At version 120, there is a failure and the database administrator restores the database with data loss. После завершения восстановления таблица содержит данные до версии 70, а минимальная синхронизированная версия по-прежнему равна 50.After the restore operation, the table contains data up through version 70, and the minimum synchronized version is still 50.

    Это означает, что синхронизированное хранилище данных содержит данные, которых уже нет в первичном хранилище.This means that the synchronized data store has data that no longer exists in the primary data store.

  5. Таблица Т1 обновлялась многократно.T1 is updated many times. Текущий номер версии для нее — 130.This brings the current version to 130.

  6. Клиентское приложение синхронизируется вновь и получает номер последней синхронизации 100.The client application synchronizes again and supplies a last-synchronized version of 100. Проверка этого номера клиентом происходит успешно, так как 100 больше 50.The client validates this number successfully because 100 is greater than 50.

    Клиент получает изменения между версиями 100 и 130.The client obtains changes between version 100 and 130. В этот момент времени клиент не знает, что изменения между версиями 70 и 100 уже не те, что были прежде.At this point, the client is not aware that the changes between 70 and 100 are not the same as before. Данные клиента и сервера не синхронизированы.The data on the client and server are not synchronized.

Обратите внимание, что если бы база данных была восстановлена на момент времени после версии 100, то проблем с синхронизацией не возникло бы.Note that if the database was recovered to a point after version 100, there would be no problems with synchronization. Клиент и сервер должны правильно синхронизировать данные во время следующего интервала синхронизации.The client and server would synchronize data correctly during the next synchronization interval.

Отслеживание изменений не помогает в случае необходимости восстановления утраченных данных по журналу.Change tracking does not provide support for recovering from the loss of data. Однако существует две возможности обнаружения проблем синхронизации такого рода.However, there are two options for detecting these types of synchronization issues:

  • Сохраните идентификатор версии базы данных на сервере и обновляйте это значение при каждом восстановлении данных или их потере, вызванной любыми другими причинами.Store a database version ID on the server, and update this value whenever a database is recovered or otherwise loses data. Этот идентификатор должно хранить и проверять во время синхронизации данных каждое клиентское приложение.Each client application would store the ID, and each client would have to validate this ID when it synchronizes data. При потере данных идентификаторы не совпадут, что заставит клиента произвести повторную инициализацию.If data loss occurs, the IDs will not match and the clients would reinitialize. Недостатком такого подхода является то, что клиент может проводить повторную инициализацию, которая окажется ненужной в случае, если потеря данных не пересекала границу последней синхронизации.One drawback is if the data loss had not crossed the last synchronized boundary, the client might do unnecessary reinitialization.

  • Когда клиент делает запрос об изменениях, сохраните номер последней версии синхронизации каждого клиента сервера.When a client queries for changes, record the last synchronization version number for each client on the server. При возникновении проблем с данными номера последней синхронизированной версии не совпадут.If there is a problem with the data, the last synchronized version numbers would not match. Это будет означать, что необходима повторная инициализация.This indicates that a reinitialization is required.

См. также:See Also

Отслеживание измененных данных (SQL Server) Track Data Changes (SQL Server)
Об отслеживании изменений (SQL Server) About Change Tracking (SQL Server)
Управление отслеживанием изменений (SQL Server) Manage Change Tracking (SQL Server)
Включение и отключение отслеживания изменений (SQL Server) Enable and Disable Change Tracking (SQL Server)
CHANGETABLE (Transact-SQL) CHANGETABLE (Transact-SQL)
CHANGE_TRACKING_MIN_VALID_VERSION (Transact-SQL) CHANGE_TRACKING_MIN_VALID_VERSION (Transact-SQL)
CHANGE_TRACKING_CURRENT_VERSION (Transact-SQL) CHANGE_TRACKING_CURRENT_VERSION (Transact-SQL)
WITH CHANGE_TRACKING_CONTEXT (Transact-SQL)WITH CHANGE_TRACKING_CONTEXT (Transact-SQL)