適用於:SQL Server
Azure SQL 受控執行個體
變更資料會透過資料表值函式 (TVF) 提供給變更資料擷取的取用者。 這些函數的查詢都需要兩個參數,用來定義在產生傳回結果集時可納入考量的記錄序號 (LSN) 範圍。 限制間隔的上下 LSN 值會被視為包含在間隔內部。
我們提供了許多函數,可協助您判斷查詢 TVF 時所使用的適當 LSN 值。 sys.fn_cdc_get_min_lsn 函數會傳回與擷取執行個體有效性間隔相關聯的最小 LSN。 有效期間是指其擷取執行個體目前可取得變更資料的時間區間。 sys.fn_cdc_get_max_lsn 函數會傳回有效性間隔中的最大 LSN。 sys.fn_cdc_map_time_to_lsn 和 sys.fn_cdc_map_lsn_to_time 函數可用來協助您將 LSN 值放置在傳統時間表上。
由於異動資料擷取會使用封閉的查詢間隔,因此有時候必須在序列中產生下一個 LSN 值,以便確保連續的查詢視窗中不會有重複的變更。 當您需要針對 LSN 值進行累加式調整時, sys.fn_cdc_increment_lsn 和 sys.fn_cdc_decrement_lsn 函數就很有用。
驗證 LSN 界限
我們建議您先驗證即將用於 TVF 查詢中的 LSN 界限,然後再加以使用。 Null 值端點,或落在擷取執行個體有效區間之外的端點,都會導致變更資料擷取 TVF 傳回錯誤。
例如,當用來定義查詢間隔的參數無效或超出範圍,或者資料列篩選選項無效時,系統就會針對所有變更的查詢傳回下列錯誤。
Msg 313, Level 16, State 3, Line 1
An insufficient number of arguments were supplied for the procedure or function cdc.fn_cdc_get_all_changes_ ...
針對 net changes 查詢傳回的對應錯誤如下所示:
Msg 313, Level 16, State 3, Line 1
An insufficient number of arguments were supplied for the procedure or function cdc.fn_cdc_get_net_changes_ ...
注意
已確認 Msg 313 的訊息具有誤導性,且未傳達失敗的實際原因。 這種彆扭的用法源於無法在 TVF 內部明確地引發錯誤。 不過,我們認為傳回可辨識 (但不正確) 錯誤的價值會比單獨傳回空白結果的價值更高。 空白的結果集與沒有傳回任何變更的有效查詢並無差別。
查詢所有變更時,若發生授權失敗,會傳回失敗結果,如下所示:
Msg 229, Level 14, State 5, Line 1
The SELECT permission was denied on the object 'fn_cdc_get_all_changes_...', database 'MyDB', schema 'cdc'.
查詢淨變更時也是如此:
Msg 229, Level 14, State 5, Line 1
The SELECT permission was denied on the object fn_cdc_get_net_changes_...', database 'MyDB', schema 'cdc'.
在 SQL Server Management Studio 中,請參閱範本 使用 TRY CATCH 列舉網路變更 ,以示範如何攔截這些已知的 TVF 錯誤,並傳回有關失敗的更有意義的資訊。
小提示
若要在 SQL Server Management Studio 中尋找變更資料擷取範本,請在 [ 檢視 ] 功能表上,選取 [範本總管],展開 [SQL Server 範本] ,然後展開 [變更資料擷取] 資料夾。
查詢函數
系統會根據所追蹤之來源資料表的特性以及其擷取執行個體的設定方式,產生一個或兩個 TVF 以便查詢變更資料。
cdc.fn_cdc_get_all_changes_<capture_instance> 函式會傳回在指定間隔中發生的所有變更。 系統一定會產生這個函數。 傳回的項目一律會經過排序 (先依據變更的交易認可 LSN,然後再依據變更在交易內部排列順序的值)。 根據選擇的資料列篩選選項,系統會在更新時傳回最後一個資料列 (資料列篩選選項 "all") 或在更新時傳回全新和舊的值 (資料列篩選選項 "all update old")。
-
注意
只有當來源資料表具有已定義的主索引鍵,或者 @index_name 參數已經用來識別唯一的索引時,才支援這個選項。
此函式會針對每個已修改的來源資料表列
netchanges傳回一個變更。 如果在指定的間隔期間記錄了資料列的多個變更,資料行值將會反映資料列的最終內容。 為了正確識別更新目標環境所需執行的作業,TVF 必須同時考量在該時間區間內對資料列執行的初始作業,以及對資料列執行的最終作業。 指定資料列篩選選項 'all' 時,淨變更查詢所傳回的作業會是插入、刪除或更新(新值)。 此選項一律會將更新遮罩傳回為 null,因為計算彙總遮罩會產生成本。 如果您需要可反映某資料列所有變更的匯總遮罩,請使用 'all with mask' 選項。 如果下游處理不需要區分插入和更新,請使用 'all with merge' 選項。 在此情況下,作業值只會使用兩個值:1 用於刪除,而 5 用於可以是插入或更新的作業。 這個選項可以排除判斷衍生之作業是插入還是更新的額外處理需求,因此可以在不需要加以區分時,增進查詢的效能。
從查詢函式傳回的更新遮罩是一種精簡表示,用來識別變更資料某個資料列中所有已變更的資料行。 通常,只有已擷取資料行中的一小部分需要這項資訊。 提供了一些函數,可協助以應用程式可更直接使用的形式,從遮罩中擷取資訊。 sys.fn_cdc_get_column_ordinal 函數會針對給定的擷取執行個體,傳回具名資料行的序數位置,而 sys.fn_cdc_is_bit_set 函數則會根據傳入函數呼叫中的序數,傳回提供之遮罩中的同位位元。 這兩個函數結合使用時,可有效率地從更新遮罩中擷取資訊,並隨變更資料請求一併傳回。 在 SQL Server Management Studio 中,請參閱範本 Enumerate Net Changes Using All With Mask ,以示範如何使用這些函式。
查詢函數情境
下列各節說明使用查詢函式 cdc.fn_cdc_get_all_changes_<capture_instance> 和 cdc.fn_cdc_get_net_changes_<capture_instance>來查詢變更資料擷取資料的常見案例。
查詢擷取實例有效期間內的所有變更
要求變更資料最直接的方式,就是傳回擷取執行個體有效期間內目前的所有變更資料。 若要提出這項要求,請先判斷有效性間隔的 LSN 下限與上限。 然後,使用這些值來識別參數 @from_lsn 並 @to_lsn 傳遞給查詢函數 cdc.fn_cdc_get_all_changes_<capture_instance> 或 cdc.fn_cdc_get_net_changes_<capture_instance>。 您可以使用 sys.fn_cdc_get_min_lsn 函數來取得下限,而使用 sys.fn_cdc_get_max_lsn 函數來取得上限。 在 SQL Server Management Studio 中,請參閱範本列 舉有效範圍的所有變更 ,以取得範例程式碼,以使用查詢函式 cdc.fn_cdc_get_all_changes_<capture_instance>查詢所有目前有效的變更。 在 SQL Server Management Studio 中,請參閱範本列 舉有效範圍的淨變更 ,以取得使用函式 cdc.fn_cdc_get_net_changes_<capture_instance>的類似範例。
查詢自上一組變更以來的所有新變更
對於一般應用程式而言,查詢變更資料是持續進行的程序,並且針對自從上一個要求以來發生的所有變更提出定期要求。 您可以針對這類查詢使用 sys.fn_cdc_increment_lsn 函數,以便從上一個查詢的上限衍生出目前查詢的下限。 這個方法可確保不會重複任何資料列,因為查詢間隔永遠會被視為封閉的間隔,其中兩個端點都包含在間隔中。 然後,您可以使用 sys.fn_cdc_get_max_lsn 函數來取得新要求間隔的高端點。 在 SQL Server Management Studio 中,請參閱範本列 舉自上次要求以來的所有變更, 以取得範例程式碼,以系統地移動查詢視窗,以取得自上次要求以來的所有變更。
查詢所有截至目前為止的新更改
針對查詢函數所傳回之變更放置的一般條件約束是僅包含上一個要求到目前日期和時間之間發生的變更。 對於此查詢,請將函數 sys.fn_cdc_increment_lsn 套用至 @from_lsn 前一個請求中使用的值,以判斷下限。 由於時間間隔的上限會表示成特定時間點,所以它必須轉換成 LSN 值,然後才能讓查詢函數使用。 在將此日期時間值轉換為對應的 LSN 值之前,您必須確定擷取處理序已處理截至指定上限為止所有已認可的變更。 這是為了確保所有符合條件的變更都已傳送到變更資料表中。 其中一種作法是建立一個會定期檢查的等待迴圈,以檢查任何資料庫變更資料表中記錄的目前最大認可 LSN 是否已超過要求區間的目標結束時間。
在延遲迴圈確認擷取程序已處理完所有相關的記錄項之後,請使用函數 sys.fn_cdc_map_time_to_lsn 判定以 LSN 值表示的新高端點。 若要確保擷取透過指定時間提交的所有項目,請呼叫函數 sys.fn_cdc_map_time_to_lsn,並使用選項 '最大且小於或等於'。
注意
在閒置期間,會將虛擬項目新增至表格 cdc.lsn_time_mapping ,以標示擷取處理程序已處理變更至給定確定時間的事實。 這可避免在其實只是沒有任何最近的變更需要處理時,讓人以為擷取程序已經落後了。
該範本列舉截至目前為止的所有變更,示範如何使用先前的策略來查詢變更數據。
將提交時間新增至「所有變更」結果集
在資料庫變更資料表中具有對應項目的每筆交易,其認可時間可在資料表 cdc.lsn_time_mapping 中取得。 透過將所有變更要求中傳回的 __$start_lsn 值與表格項目的 cdc.lsn_time_mapping start_lsn 值結合,您可以傳回 tran_end_time 與變更資料一起,並使用來源的交易確定時間來標記變更。 範本將 認可時間附加至所有變更結果集 示範如何執行此聯結。
將變更資料與相同交易中的其他資料聯結
有時,將變更資料與交易在來源端提交時所蒐集的其他相關資訊結合,會很有用。
tran_begin_lsn表格cdc.lsn_time_mapping中的直欄提供執行此類聯結所需的資訊。 更新來源時,來自 sys.dm_tran_database_transactions 系統動態檢視的 database_transaction_begin_lsn 值必須與要和變更資料聯結的任何其他資訊一起儲存。 使用函數 fn_convertnumericlsntobinary 來比較 database_transaction_begin_lsn 和 tran_begin_lsn 值。 建立此函式的程式碼可在範本 建立函式 fn_convertnumericlsntobinary中找到。 範本 Return All Changes with a Given tran_begin_lsn 示範如何影響合併。
使用 DateTime 包裝函式進行查詢
查詢變更資料的一般應用程式狀況是使用以日期時間值所限定的滑動視窗來定期要求變更資料。 對於這類取用者,異動資料擷取提供 sys.sp_cdc_generate_wrapper_function 預存程序,用來產生可為異動資料擷取查詢函數建立自訂包裝函數的指令碼。 這些自訂包裝函數可讓查詢間隔表示成日期時間組。
此預存程序的呼叫選項可讓您針對呼叫者可存取的所有擷取執行個體或只針對指定的擷取執行個體產生包裝函數。 支援的選項還包括可指定擷取區間的上限端點為開區間或閉區間、可用的擷取資料行中哪些應包含在結果集中,以及哪些已包含的資料行應具有相關的更新旗標。 此程序會傳回一個含有兩個資料行的結果集:產生的函數名稱(可從擷取執行個體名稱推導而得),以及包裝預存程序的 CREATE 陳述式。 系統一定會產生可包裝所有變更查詢的函數。 如果建立擷取執行個體時已設定 @supports_net_changes 參數,也會產生用來包裝淨變更函式的函式。
呼叫指令碼產生預存程序,以產生用於建立包裝預存程序的 CREATE 陳述式,並執行產生的建立指令碼來建立這些函式,這是應用程式設計人員的責任。 這項作業不會在建立擷取執行個體時自動進行。
日期時間包裝函數是由使用者所擁有,並非建立在呼叫者的預設結構描述中。 產生的函數不需要修改就可適用於大部分使用者。 不過,建立此函數之前,您隨時都可以將進一步的自訂套用至產生的指令碼。
包裝所有變更查詢的函式名稱是 fn_all_changes_,後接擷取執行個體名稱。 用於網路變更包覆器的字首是 fn_net_changes_。 這兩個函數都接受三個引數,就像其對應的異動資料擷取 TVF 一樣。 不過,這些包裝函數的查詢間隔是以兩個日期時間值 (而非兩個 LSN 值) 所限定。 這兩組函式的 @row_filter_option 參數都相同。
產生的包裝函式支援以下慣例,以系統化方式逐步走訪異動資料擷取時間軸:預期會將前一個區間的 @end_time 參數用作後一個區間的 @start_time 參數。 此包裝函數會負責將日期時間值對應至 LSN 值,並且確保遵循此慣例時,不會遺漏或重複任何資料。
您可以產生包裝函數來支援指定之查詢視窗上的封閉上限或開放上限。 也就是說,呼叫者可以指定提交時間等於擷取區間上限的項目是否應包含在該區間內。 預設情況下,包含上限值。
當產生的查詢 TVF 失敗時,如果針對 @from_lsn 值或 @to_lsn 值提供 Null 值,日期時間包裝函式就會使用 Null 來允許日期時間包裝函式傳回所有目前的變更。 也就是說,如果 null 作為查詢視窗的低端點傳遞至 datetime 封裝函式,則會在應用至查詢 TVF 的底層SELECT陳述式中使用擷取實例有效期間的低端點。 同樣地,如果將 null 傳遞為查詢視窗的上限端點,則在從查詢 TVF 選取資料時,會使用擷取執行個體有效區間的上限端點。
包裝函式所傳回的結果集包含所有要求的資料行,後面接著一個作業資料行,其內容會重新編碼為一或兩個字元,以識別與該資料列相關聯的作業。 如果已經要求更新旗標,它們就會按照 @update_flag_list 參數中指定的順序,在作業碼之後顯示成位元資料行。 如需用來自訂所產生日期時間包裝函式的呼叫選項相關資訊,請參閱 sys.sp_cdc_generate_wrapper_function (Transact-SQL)。
範本 Instantiate a Wrapper TVF With Update Flag 顯示如何自訂產生的包裝函式,以將指定資料行的更新旗標附加至淨變更查詢所傳回的結果集。 範本實 例化結構描述的 CDC 包裝函式 TVF 顯示如何實例化針對指定資料庫結構描述中來源資料表建立的所有擷取執行個體的查詢 TVF 的日期時間包裝函式。
如需使用日期時間包裝函式來查詢變更資料的範例,請在 SQL Server Management Studio 中參閱範本 使用包裝函式搭配更新旗標取得淨變更。 此範本示範當包裝函數設定為傳回更新旗標時,如何使用該函數查詢淨變更。 基礎查詢函式需要資料列篩選選項 'all with mask',才能在更新時傳回非 Null 更新遮罩。 會傳遞下限和上限日期時間間隔界限的 Null 值,以指示函式在執行基礎 LSN 型查詢時,使用擷取執行個體有效性間隔的低端點和高端點。 此查詢會針對擷取執行個體有效範圍內發生的每一次來源資料列修改,傳回一個資料列。
使用 DateTime 包裝函式在擷取實例之間轉換
對於單一追蹤來源資料表而言,異動資料擷取最多支援兩個擷取執行個體。 這項功能的主要用途是在來源資料表的資料定義語言 (DDL) 變更擴充可用於追蹤的資料行集合時,容納多個擷取執行個體之間的轉換。 當轉換至新的擷取執行個體時,若要保護較高層級的應用程式不受底層查詢函式名稱變更的影響,其中一種做法是使用包裝函式來封裝底層呼叫。 然後,請確定包裝函數的名稱維持不變。 要進行切換時,可以移除舊的包裝函數,並建立一個同名的新包裝函數來引用新的查詢函數。 您只要先修改產生的指令碼,使其建立一個同名的包裝函式,就能在不影響上層應用程式的情況下切換到新的擷取執行個體。