変更の追跡のしくみ (SQL Server)Work with Change Tracking (SQL Server)

適用対象: ○SQL Server (2008 以降) ○Azure SQL Database XAzure SQL Data Warehouse XParallel Data Warehouse APPLIES TO: yesSQL Server (starting with 2008) 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() functionCHANGE_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. 期間の長さは、ALTER DATABASE の一部として指定できる CHANGE_RETENTION パラメーターで制御されます。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 …) を使用して変更を取得する前に、CHANGETABLE(CHANGES …) に渡す予定の last_synchronization_version の値を検証する必要があります。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. たとえば、サイズは大きいが変更頻度は低い 1 つ以上の列と、頻繁に変更される他の列で構成されるテーブルのシナリオについて考えてみます。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.

列追跡情報は、CHANGETABLE(CHANGES …) 関数によって返される SYS_CHANGE_COLUMNS 列に表示されます。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. CHANGETABLE(CHANGES ...) を使用して Sales テーブルの変更を取得します。Obtain the changes for the Sales table by using CHANGETABLE(CHANGES ...).

  4. CHANGETABLE(CHANGES ...) を使用して SalesOrders テーブルの変更を取得します。Obtain the changes for the SalesOrders table by using CHANGETABLE(CHANGES ...).

データベースで実行される次の 2 つのプロセスが、上記の手順で返される結果に影響する場合があります。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.

  • 継続的な DML 操作として、Sales テーブルと SalesOrders テーブルで次のような操作が実行されます。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. CHANGETABLE(CHANGES …) を使用して Sales テーブルの変更を取得します。Obtain the changes for the Sales table by using CHANGETABLE(CHANGES ...)

  5. CHANGETABLE(CHANGES ...) を使用して SalesOrders テーブルの変更を取得します。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. CHANGETABLE() の呼び出し後に last_synchronization_version を確認します。Check last_synchronization_version after the calls to CHANGETABLE().

  2. CHANGETABLE() を使用して変更を取得する各クエリで、その一部として last_synchronization_version を確認します。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. この状況に対処するには、2 つの方法があります。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.

上記の 2 つのオプションに加え、操作に応じて両方を組み合わせた方法を検討することもできます。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. たとえば変更のソースとなったデータ ストアの ID は、このコンテキスト情報の一例です。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. 格納した情報は、CHANGETABLE(CHANGES ...) によって返される SYS_CHANGE_CONTEXT 列から取得できます。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. テーブル T1 は変更の追跡の対象になっており、このテーブルの有効な最小バージョンは 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. テーブル T1 には、バージョン 100 以降もさらに変更が加えられます。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. T1 は何度も更新されます。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. ただし、この種の同期の問題を検出する方法は 2 つあります。However, there are two options for detecting these types of synchronization issues:

  • データベース バージョン ID をサーバーに保存し、データベースの復旧などでデータが失われるたびに、この値を更新する方法。Store a database version ID on the server, and update this value whenever a database is recovered or otherwise loses data. この ID を各クライアント アプリケーションに保存し、各クライアントがデータを同期する際に必ず検証されるようにします。Each client application would store the ID, and each client would have to validate this ID when it synchronizes data. データ損失が発生した場合は ID が一致しなくなり、クライアントが再初期化されます。If data loss occurs, the IDs will not match and the clients would reinitialize. 1 つの欠点は、データ損失が最後に同期された範囲に及んでいない場合に、不要な再初期化が行われる可能性があることです。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)