트랜잭션 복제를위한 ID 범위 다루기


9

트랜잭션 복제를 설정하면 SQL Server가 ID 범위 관리를 수동으로 설정합니다. 이것은 구독 데이터베이스에서 PK가 ID 열인 테이블에 새 레코드를 삽입하려고 할 때 오류가 발생하고 PK "1", "2를 삽입하려고 시도했다는 의미입니다. ","3 "등입니다. 이는 구독자의 모든 ID 열에 대한 현재 ID 값이 게시자의 값을 유지하지 않고 시드 값 (일반적으로 1)으로 재설정되기 때문입니다.

SQL Server가 왜 그렇게하는지 이해합니다. 가입자 테이블을 읽기 전용으로 남겨 두어야합니다. 그러나 내 시나리오는 약간 정통적입니다. 복제를 통해 구독자를 수시로 업데이트하고 해당 DB를 즉시 백업 한 다음 구독자에게 다시 업데이트하지 말고 구독자에게 업데이트를하고 싶습니다. 구독자를 다시 업데이트하려고하면 이전 백업에서 데이터베이스를 복원하고 최신 업데이트를 가져옵니다. 이 업데이트 사이에 구독자에게 업데이트를 원하기 때문에 (필요한 경우 '임시 델타') 복제 할 때 ID 열이 작동하고 1로 재설정하지 않아야합니다.

게시를 설정할 때 자동 ID 범위 관리를 설정하려고 시도했지만 게시에 테이블을 추가하려고 할 때 다음 오류가 발생합니다.

메시지 21231, 수준 16, 상태 1, 절차 sp_MSrepl_addarticle, 줄 2243
자동 ID 범위 지원은 구독자를 업데이트 할 수있는 게시에만 유용합니다.

이 문제를 해결할 수있는 방법이 있습니까? 게시자에게 푸시되는 업데이트 계획하지 않기 때문에 구독자 쪽에서 읽기 전용 인 것처럼이 복제를 SQL Server에 제공 하려고하지만 임시 업데이트를 하고 싶습니다. 다음 복제 전에 지워집니다.

또한 스냅 샷 복제가 사용 패턴에 대한 트랜잭션 복제보다 더 적절한 방법이라고 생각했지만 스냅 샷 복제는 단일 업데이트마다 전체 DB를 전송해야한다는 문제가 있습니다 . 최신 복제 후 DB를 즉시 백업 할 계획이므로 매번 전체 전송을 수행 할 필요는 없습니다. 지난번 이후의 변화.


어떤 버전의 SQL Server를 사용하고 있습니까? 테이블을 재정의 할 수 있습니까?

2008 년 r2. 테이블을 재정의하면이 문제가 어떻게 해결 될지 모르겠습니다.
Jez

SEQUENCE를 사용하는 솔루션을 생각했지만 SQL 2012에만 해당됩니다.

2
Is there any way I can get round this problem?SQL Server 2005 이상 에서는 sys.sp_identitycolumnforreplication 을 사용하여 ID 열을 NOT FOR REPLICATION 으로 설정해야 합니다. ID 열을 복제 용이 아닌 것으로 변경할 때 기사를 다시 스냅 샷하지 않아도됩니다. GUI를 사용하여하지 마십시오.
Kin Shah

이미 복제 용으로 표시되지 않았습니다. 그것은 기본적으로 문제입니다-SQL Server는 ID 정보를 복사하지 않으므로 가입자는 1에서 다시 시작합니다.
Jez

답변:


3

게시자가 1에서 시작하는 int ID를 사용한다고 가정하면 DBCC CHECKIDENT('dbo.mytable', RESEED, -2147483648) 구독자에게 발급 할 수 있습니다. 그런 다음 -2147483648에서 0까지의 범위를 사용하여 "임시 델타"를 보유 할 수 있습니다.


이것이 내가 제안한 솔루션이지만 여전히 게시자 및 구독자에게 연결하고 ID를 수동으로 동기화하는 코드를 의미합니다. 더 자동적 인 방법이 있기를 바랐습니다.
Jez

ID를 수동으로 동기화해야하는 이유는 무엇입니까? 임시 델타를 저장하는 각 테이블에 대해 checkident를 실행하는 구독자에 저장 프로 시저를 작성하고 스냅 샷 적용이 완료된 후에 실행하십시오. 배포 에이전트는 "실제"ID 범위에서 발생하는 변경 사항을 삽입하고 가입자에게 직접 변경 한 내용은 음수 범위에있게됩니다.
Liam Confrey

1

내가 한 일은 풀 기반 트랜잭션 복제를 고수하고 내 프로그램이 구독자 ID 값을 동기화 직후 게시 데이터베이스의 값과 동일하게 업데이트하도록하는 것입니다 (배포 에이전트가 자체적으로 원하는 것을 따라야 함) ). 의사 코드에서는 다음과 같이 보입니다.

synchronize databases with TransSynchronizationAgent

equivalentTablesNotFound is a list of strings
for each table in publisher tables:
    try:
        check table identity value (this is via functionality provided by .NET's Microsoft.SqlServer.Management.Smo.Server class)
        parse identity value as integer to newIdentity
        if the table's identity value was NULL, skip to next loop iteration
        (HACK) increment newIdentity value by 1
        if there is no subscriber table with the same name as this one:
            record its name in equivalentTablesNotFound and skip to next loop iteration
        set subscriber table with same name's identity value to newIdentity using TSQL: DBCC CHECKIDENT ("tableName", newIdentity)
    catch:
        if exception shows that the error was because the table doesn't have an identity column, drop the exception

if equivalentTablesNotFound has more than zero entries, warn about tables on publisher without an equivalent name on subscriber

작동하는 것 같습니다. HACK 비트는 기본적으로 모든 테이블에서 ID 값이 1 씩 증가하지만 다르게 구성 할 수 있기 때문에 기술적으로 게시자 테이블에서 ID 값이 증가하는 방법을 찾아야합니다. 같은 길.


0

이것을 처리하기 위해 내가 선호하는 방법은 다음을 수행하는 것입니다.

ㅏ. 먼저 복제 에이전트를 중지하십시오 (따라서 구독자 DB에 새로운 데이터가 표시되지 않음)

비. 두 번째로 기존 테이블의 이름을 바꿉니다.

exec sp_rename '[CurrentTable]', '[BackupTableName]'

씨. IDENTITY 세트로 테이블을 다시 작성하십시오.

CREATE TABLE [CurrentTable]
(
   ID INT NOT NULL IDENTITY(1,1), 
   OtherField VARCHAR(10) NULL,
   ....
)

디. SET IDENTITY_INSERT로 [BackupTableName]에서 테이블을 채우십시오.

SET IDENTITY_INSERT [CurrentTable] ON
INSERT INTO [CurrentTable] (ID, OtherField, ...)
SELECT ID, OtherField, ....
FROM [BackupTableName]
SET IDENTITY_INSERT [CurrentTable] OFF

당신은 일단 IDENTITY의 사용자 DB에 제약을, 다음 중 하나를 사용자 정의 복제를 할 수 있습니다 (예 : SET IDENTITY_INSERT [TABLENAME] ON에 삽입 REPL proc 디렉토리를 변경하거나 SQL 서버가 알려주는 테이블에 복제 플래그 (대한 NOT 설정할 수 있습니다 연결 사용자가 복제 에이전트 인 경우, ()는 IDENTITY 값이 공급 될 것으로 예상 그것이 나에게 더 많은 유연성을 제공로서 나는, 사용자 정의 복제 방식을 선호 )

이자형. 삽입 복제 저장 프로 시저 (일반적으로 sp_MSins_CurrentTable)를 수정하여 삽입SET IDENTITY INSERT

ALTER procedure [dbo].[sp_MSins_CurrentTable]
    @c1 int, @c2 varchar(50), ...
as
begin
    /* allow replication to insert values for IDENTITY */
    SET IDENTITY_INSERT [CurrentTable] ON
    insert into [CurrentTable]
        ([ID], [OtherField], ...)
    values
        (@c1, @c2, ...)
    /* now turn off Identity insert */
    SET IDENTITY_INSERT [CurrentTable] OFF
end

에프. 이제 복제 에이전트를 다시 시작할 수 있습니다.


1
lol을 사용하는 것과 비교할 DBCC CHECKIDENT때이 방법은 엄청난 양의 작업입니다.
Jez

@Jez DBCC CHECKIDENT를 실행하려면 테이블 (IDENTITY 포함)을 다시 만들어야합니다 ... 복제 스냅 샷은 IDENTITY 제약 조건없이 테이블을 생성합니다 (q에 따라 DBCC CHECKIDENT는 작동하지 않음)
Andrew Bickerton

참고로 그것은 작동했고 복제는 IDENTITY 제약 조건을 가진 테이블을 만듭니다 ...
Jez

@Jez 어떤 유형의 복제를 설정 했습니까? (이를 MERGE로 설정하면 TRANSACTIONAL의 경우 GUI를 사용하지 않으면 복제를 사용자 정의 할 수 있지만 일반적으로 그렇지 않습니다.)
Andrew Bickerton

거래. 내가 말했듯이 IDENTITY는 있지만 현재 ID 값은 시드 값 (1)으로 재설정됩니다.
Jez
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.