Replication的犄角旮旯(五)--關於復制identity列


 

 

《Replication的犄角旮旯》系列導讀

Replication的犄角旮旯(一)--變更訂閱端表名的應用場景

Replication的犄角旮旯(二)--尋找訂閱端丟失的記錄

Replication的犄角旮旯(三)--聊聊@bitmap

Replication的犄角旮旯(四)--關於事務復制的監控

Replication的犄角旮旯(五)--關於復制identity列

Replication的犄角旮旯(六)-- 一個DDL引發的血案(上)(如何近似估算DDL操作進度)

Replication的犄角旮旯(七)-- 一個DDL引發的血案(下)(聊聊logreader的延遲)

Replication的犄角旮旯(八)-- 訂閱與發布異構的問題

Replication的犄角旮旯(九)-- sp_setsubscriptionxactseqno,賦予訂閱活力的工具

---------------------------------------華麗麗的分割線--------------------------------------------

 

今天被群友問到復制環境中identity屬性的問題。在此通過幾個測試說明一下identity列是如何在復制環境中實現的;

以下測試均是基於SQLSERVER 2012 SP1下的事務復制環境;

先拋出幾個測試目的;

1、identity列和not for replication的關系,發布端及訂閱端何時添加not for replication屬性

2、快照初始化、備份初始化、不初始化訂閱對not for replication參數的依賴

3、如何添加not for replication,在哪添加not for relication,以及替代not for replication的方法

 

先解釋一下not for replication

NOT FOR REPLICATION

在 CREATE TABLE 語句中,可為 IDENTITY 屬性、FOREIGN KEY 約束和 CHECK 約束指定 NOT FOR REPLICATION 子句。 如果為 IDENTITY 屬性指定了該子句,則復制代理執行插入時,標識列中的值將不會增加。 如果為約束指定了此子句,則當復制代理執行插入、更新或刪除操作時,將不會強制執行此約束。

http://msdn.microsoft.com/zh-cn/library/ms174979.aspx

簡單說,對於identity、外鍵約束、check約束,可以通過指定not forreplication避免訂閱端寫入數據失敗;

 

測試開始:

  先在同一個實例下創建兩個庫test_byxl_1、test_byxl_2,分別作為本次測試的發布庫和訂閱庫;

  

  test_byxl_1下創建tb_ident_1表,結構如下

1 create table test_byxl_1.dbo.tb_ident_1 (id int primary key identity ,name varchar(10))
View Code

  添加這個表的發布,只創建publication、添加article即可;

  

  注意:默認的article屬性中對identity的管理是手動的,這里默認即可;

  然后再來看一下這個表的屬性,已經開啟了發布表的not for replication屬性;

  

  這時候再添加訂閱,並通過快照初始化,訂閱端也同樣有這個屬性

  

  

  這種按照默認配置並通過快照方式初始化的情況,可以滿足identity列的同步問題;這也是最常見的情況;

===================華麗麗的分割線========================

但如果是備份初始化或者不初始化呢?

由於通過備份初始化的訂閱端,不會主動添加not for replication子句,因此需要手動添加not for replication子句

alter table tb_ident_1 alter column id add not for replication

對於不初始化的情況,要么在create table的時候對identity列添加not for replication屬性,要么同備份初始化一樣,在同步前通過alter table 的方式添加not for replication屬性;

 

===================華麗麗的分割線========================

 

有同學繼續問到:那發布端一定需要not for replication屬性么?

答案是no!

但為什么添加發布的時候,系統會在發布表上添加not for replication屬性呢?

答案是為了方便今后通過快照初始化的訂閱可以順利擁有not for replication屬性。因為在創建publication並添加article時,發布服務器並不需要也沒有必要知道你即將在這個publication里添加什么類型的訂閱;因此為了方便,就在創建publication的時候,檢查每個article是否擁有identity列,並自動加上not for publication屬性;

為此,我做了個測試來驗證第一個問題(發布端一定需要not for replication屬性么?)

測試開始:

  首先,在發布端刪掉not for publication屬性

alter table test_byxl_1.dbo.tb_ident_1 alter column id drop not for replication

  觀察一下發布表和訂閱表的屬性,可以看到發布端的not for replication已經被刪掉,而這個語句並沒有被復制到訂閱端,因此訂閱端的not for replication屬性仍然存在;

  

 

  

  發布端寫入一條測試數據,並檢查發布端、訂閱端數據,可以發現可以正常同步到訂閱端;因此驗證了上面的問題(發布端一定需要not for replication屬性么?);

  set identity_insert test_byxl_1.dbo.tb_ident_1 on 
  insert into test_byxl_1.dbo.tb_ident_1(id,name) values(10,'beijing')
  set identity_insert test_byxl_1.dbo.tb_ident_1 off

  select * from  test_byxl_1.dbo.tb_ident_1
  select * from  test_byxl_2.dbo.tb_ident_1

  

 

===================華麗麗的分割線========================

 

我們再來做個測試;先驗證一下,當訂閱端沒有not for replication時,會發生什么情況;

為此,我分別在發布、訂閱端創建了了一個tb_ident_2表,並創建不初始化的訂閱

create table test_byxl_1.dbo.tb_ident_2 (id int primary key identity ,name varchar(10))
create table test_byxl_2.dbo.tb_ident_2 (id int primary key identity ,name varchar(10))

發布端自動添加了not for replication屬性,而訂閱端由於手動創建,沒有這個屬性

  

  

  插入測試數據

  set identity_insert test_byxl_1.dbo.tb_ident_2 on 
  insert into test_byxl_1.dbo.tb_ident_2(id,name) values(11,'shanghai')
  set identity_insert test_byxl_1.dbo.tb_ident_2 off

  select * from  test_byxl_1.dbo.tb_ident_2
  select * from  test_byxl_2.dbo.tb_ident_2

  大約1分鍾以后,分發代理job開始重試

  

  檢查distribution.dbo.msrepl_errors表,出現identity_insert的錯誤

  

  手動添加訂閱端的not for replication屬性,為了能快速看到效果,再手動啟停一下分發代理作業;  

  alter table test_byxl_2.dbo.tb_ident_2 alter column id add not for replication

  檢測訂閱端數據,發現數據已同步到訂閱端;

  

 

===================華麗麗的分割線========================

 

最后一個測試,有沒有替代not for replication的方法?

我們先去掉tb_ident_2訂閱端的not for replication屬性

  alter table test_byxl_2.dbo.tb_ident_2 alter column id drop not for replication

然后修改訂閱端對tb_ident_2表的ins存儲過程,手動在insert語句前后添加identity_insert開關;

  

  執行保存后,再寫入測試數據;訂閱端已接收到最新數據;

  

 

===================華麗麗的分割線========================

結論:

1、not for replication只有在訂閱表上添加時才有效,發布表在創建發布時由系統添加只是為了快照初始化訂閱時可以方便表結構同步;

2、not for replication屬性,可以在create table時創建,也可以通過alter table XXX alter column ident_col add not for replication的方式后期添加;

3、通過快照初始化訂閱時,不必關心identity列的同步問題,默認設置就好;

4、可以通過其他方法替代alter table XXX alter column ident_col add not for replication(如修改訂閱端存儲過程),但強烈不推薦;原因,你懂的……

 

歡迎拍磚

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM