Trattare con intervalli di identità per la replica transazionale


9

Ho notato che quando si imposta una replica transazionale, SQL Server imposterà la gestione dell'intervallo di identità su manuale. Ciò significa che nel mio database di abbonamenti, quando provo a inserire un nuovo record in una tabella il cui PK è una colonna di identità, mi darà un errore e dirò che ha provato a inserire un PK di "1", "2 "," 3 ", ecc. Questo perché il valore di identità corrente per tutte le colonne di identità sull'abbonato viene reimpostato sul valore di seed (di solito 1) anziché rimanere su quello che era sull'editore.

Capisco perché SQL Server fa questo: dovresti lasciare la tabella degli abbonati in sola lettura. Tuttavia, il mio scenario è un po 'poco ortodosso: di tanto in tanto aggiorno il mio abbonato attraverso la replica, eseguo un backup immediato di quel DB, quindi voglio fare alcuni aggiornamenti al sottoscrittore che NON VERRANNO essere rispediti all'editore, quindi quando vado di nuovo ad aggiornare l'abbonato, ripristino il suo database dal backup precedente ed estraggo gli ultimi aggiornamenti. Dato che voglio fare aggiornamenti al sottoscrittore tra questi aggiornamenti ("delta temporanea" se vuoi), ho bisogno che la colonna identità funzioni e non resetta a 1 quando viene replicata.

Ho provato ad attivare la gestione automatica dell'intervallo di identità durante l'impostazione della mia pubblicazione, ma ciò mi dà il seguente errore quando provo ad aggiungere una tabella alla pubblicazione:

Messaggio 21231, livello 16, stato 1, procedura sp_MSrepl_addarticle, riga 2243 Il
supporto automatico dell'intervallo di identità è utile solo per le pubblicazioni che consentono l'aggiornamento degli abbonati.

C'è un modo per aggirare questo problema? Voglio presentare questa replica a SQL Server come se fosse di sola lettura alla fine dell'abbonato perché non intendo fare aggiornamenti che verranno restituiti al publisher , ma voglio fare aggiornamenti temporanei che verrà cancellato prima della replica successiva.

Ho anche considerato che la replica di snapshot potrebbe essere un metodo più appropriato rispetto alla replica transazionale per il mio modello di utilizzo, ma il problema è che la replica di snapshot richiede l'invio dell'intero darn DB ad ogni singolo aggiornamento; poiché sto pianificando di eseguire un backup immediato del DB dopo l'ultima replica, non dovrei aver bisogno di eseguire l'intero trasferimento ogni volta; solo i cambiamenti dall'ultima volta.


Quale versione di SQL Server stai usando? Puoi ridefinire il tavolo?

2008 r2. Non vedo come ridefinire la tabella risolverebbe questo problema ...
Jez

Stavo pensando a una soluzione utilizzando SEQUENCE, ma è solo per SQL 2012.

2
Is there any way I can get round this problem?Devi impostare la colonna Identity come NOT FOR REPLICATION usando sys.sp_identitycolumnforreplication per SQL Server 2005 e versioni successive. Non è nemmeno necessario ripetere la ripresa degli articoli quando si cambia la colonna identità come non per la replica. Non farlo usando la GUI.
Kin Shah,

È già contrassegnato come non per la replica. Questo è fondamentalmente il problema: SQL Server non copia le informazioni sull'identità, quindi sull'abbonato inizia da 1.
Jez

Risposte:


3

Supponendo che il tuo editore stia utilizzando un'identità int che inizia da 1, potresti emetterlo DBCC CHECKIDENT('dbo.mytable', RESEED, -2147483648) presso l'abbonato. È quindi possibile utilizzare l'intervallo compreso tra -2147483648 e 0 per contenere i "delta temporanei".


Questa è la soluzione che mi è venuta in mente, ma significa ancora che il mio codice si collega all'editore e al sottoscrittore e sincronizza manualmente le identità. Speravo ci fosse un modo più automatico per farlo.
Jez,

Perché dovresti sincronizzare manualmente le identità? Basta scrivere una procedura memorizzata nell'abbonato che esegue checkident per ogni tabella in cui si sta archiviando delta temporanea ed eseguirla al termine dell'applicazione dell'istantanea. L'agente di distribuzione inserirà le modifiche nel momento in cui si verificano nell'intervallo di identità "reale" e le modifiche apportate direttamente al sottoscrittore saranno nell'intervallo negativo.
Liam Confrey,

1

Quello che ho finito è stato mantenere una replica transazionale basata su pull e avere il mio programma che aggiornava i valori dell'identità dell'abbonato in modo che fossero gli stessi del database di pubblicazione immediatamente dopo la sincronizzazione (un po 'quello che vorrei che l'agente di distribuzione facesse da solo) ). In pseudo-codice sembrava un po 'così:

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

Sembra funzionare bene. Il bit HACK è perché, sebbene per impostazione predefinita e con tutte le mie tabelle, il valore dell'identità aumenta solo di uno, può essere configurato in modo diverso, quindi tecnicamente qui dovresti scoprire come il valore dell'identità aumenta sulla tabella del publisher e incrementarlo stessa strada.


0

Il mio metodo preferito per gestire questo è quello di fare quanto segue:

un. Innanzitutto, arrestare il proprio agente di replica (quindi non si stanno ottenendo nuovi dati nel proprio database di abbonati)

b. In secondo luogo rinominare la tabella esistente

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

c. Ricrea la tua tabella con IDENTITY impostato

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

d. Riempi di nuovo la tabella (da [BackupTableName]) con SET IDENTITY_INSERT

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

Una volta che hai il vincolo IDENTITY sul tuo DB, puoi eseguire la replica personalizzata (ad esempio: modifica il tuo insert insert proc in SET IDENTITY_INSERT [TableName] ON oppure puoi impostare il flag NOT FOR REPLICATION sulla tabella (che indica a SQL Server che se l'utente che si connette è l'agente di replica, si aspetta che venga fornito il valore IDENTITÀ) ( preferisco l'approccio di replica personalizzato, poiché mi dà maggiore flessibilità )

e. Modificare la procedura memorizzata per la replica di inserimento (in genere denominata sp_MSins_CurrentTable) per inserirla anche medianteSET 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

f. Ora puoi riavviare il tuo agente di replica.


1
lol, rispetto all'utilizzo DBCC CHECKIDENT, questo metodo richiede un'enorme quantità di lavoro.
Jez,

@Jez dovrai ricreare la tabella (con IDENTITY) per eseguire DBCC CHECKIDENT ... Un'istantanea della replica creerà la tabella senza il vincolo IDENTITY (in base alla tua q direi che DBCC CHECKIDENT ha vinto funziona)
Andrew Bickerton,

Cordiali saluti ha funzionato e la replica crea la tabella con il vincolo IDENTITY ...
Jez

@Jez che tipo di replica hai impostato? (se lo configuri come MERGE che accadrà, per TRANSACTIONAL di solito non lo fa, anche se la replica è altamente personalizzabile se non usi la GUI)
Andrew Bickerton,

Transazionale. Come ho già detto, l'IDENTITÀ è presente, ma il valore dell'identità corrente viene ripristinato sul valore seed (1).
Jez,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.