Manejo de rangos de identidad para la replicación transaccional


9

Me di cuenta de que cuando configura una replicación transaccional, SQL Server establecerá la administración del rango de identidad en manual. Lo que esto significa es que en mi base de datos de suscripción, cuando trato de insertar un nuevo registro en una tabla cuyo PK es una columna de identidad, me dará un error y dirá que intentó insertar un PK de "1", "2 "," 3 ", etc. Esto se debe a que el valor de identidad actual para todas las columnas de identidad en el suscriptor se restablece al valor inicial (generalmente 1) en lugar de permanecer en lo que estaba en el editor.

Entiendo por qué SQL Server hace esto: se supone que debes dejar la tabla de suscriptores como de solo lectura. Sin embargo, mi escenario es un poco poco ortodoxo: actualizo a mi suscriptor de vez en cuando a través de la replicación, hago una copia de seguridad inmediata de esa base de datos, luego quiero hacer algunas actualizaciones para el suscriptor que NO se enviarán al editor, luego cuando vuelvo a actualizar el suscriptor, restauro su base de datos de la copia de seguridad anterior y obtengo las últimas actualizaciones. Debido a que quiero hacer actualizaciones al suscriptor entre estas actualizaciones ('deltas temporales' si lo desea), necesito que la columna de identidad funcione y no se restablezca a 1 cuando se replica.

Intenté activar la administración automática del rango de identidad al configurar mi publicación, pero eso solo me da el siguiente error cuando intento agregar una tabla a la publicación:

Msg 21231, Nivel 16, Estado 1, Procedimiento sp_MSrepl_addarticle, Línea 2243
El soporte de rango de identidad automático es útil solo para publicaciones que permiten actualizar suscriptores.

¿Hay alguna forma de solucionar este problema? Quiero presentar esta replicación a SQL Server como si fuera de solo lectura al final del suscriptor porque no planeo hacer actualizaciones que serán enviadas de vuelta al editor , pero sí quiero hacer actualizaciones temporales que será borrado antes de la próxima replicación.

También he considerado que la replicación de instantáneas podría ser un método más apropiado que la replicación transaccional para mi patrón de uso, pero el problema es que la replicación de instantáneas requiere enviar toda la base de datos a cada actualización; Como estoy planeando realizar una copia de seguridad inmediata de la base de datos después de la última replicación, no debería necesitar hacer esa transferencia completa cada vez; solo los cambios desde la última vez.


¿Qué versión de SQL Server estás usando? ¿Puedes redefinir la mesa?

2008 r2. No veo cómo redefinir la mesa resolvería este problema ...
Jez

Estaba pensando en una solución usando SEQUENCE, pero eso es solo para SQL 2012.

2
Is there any way I can get round this problem?Debe establecer la columna de identidad como NO PARA REPLICAR usando sys.sp_identitycolumnforreplication para sql server 2005 y versiones posteriores. Incluso no tiene que volver a capturar sus artículos cuando cambia la columna de identidad como no para la replicación. Simplemente no lo hagas usando GUI.
Kin Shah

Ya está marcado como no para replicación. Ese es básicamente el problema: SQL Server no copia la información de identidad, por lo que en el suscriptor, comienza de nuevo a las 1.
Jez

Respuestas:


3

Suponiendo que su editor está utilizando una identidad int que comienza en 1, puede emitir DBCC CHECKIDENT('dbo.mytable', RESEED, -2147483648) en el suscriptor. Luego puede usar el rango de -2147483648 a 0 para mantener sus "deltas temporales".


Esta es la solución que se me ocurrió, pero aún significa que mi código se conecta al editor y al suscriptor y sincroniza las identidades manualmente. Esperaba que hubiera una forma más automática de hacerlo.
Jez

¿Por qué necesitarías sincronizar las identidades manualmente? Simplemente escriba un procedimiento almacenado en el suscriptor que ejecute checkident para cada tabla en la que está almacenando los delta temporales, y ejecútelo después de que la instantánea termine de aplicarse. El agente de distribución insertará los cambios a medida que ocurran en el rango de identidad "real", y los cambios realizados directamente al suscriptor estarán en el rango negativo.
Liam Confrey

1

Lo que terminé haciendo fue mantener una replicación transaccional basada en extracción y hacer que mi programa actualizara los valores de identidad del suscriptor para que fueran los mismos que los de la base de datos de publicaciones inmediatamente después de la sincronización (algo que desearía que el agente de distribución hiciera por su propia cuenta ) En pseudocódigo se parecía un poco a esto:

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

Parece funcionar bien. El bit HACK se debe a que, aunque de forma predeterminada y con todas mis tablas, el valor de identidad solo se incrementa en uno, se puede configurar de manera diferente, por lo que técnicamente aquí debe averiguar cómo aumenta el valor de identidad en la tabla del editor e incrementarlo. mismo camino.


0

Mi método preferido para manejar esto es hacer lo siguiente:

a. Primero detenga su agente de replicación (para que no obtenga datos nuevos en su DB de suscriptor)

si. Segundo renombra tu tabla existente

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

C. Vuelva a crear su tabla con el conjunto IDENTITY

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

re. Rellene su tabla (desde [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 vez que tenga la restricción IDENTITY en su base de datos, puede hacer una replicación personalizada (es decir, cambiar su proceso de inserción de respuesta a SET IDENTITY_INSERT [TableName] ON o puede establecer el indicador NOT FOR REPLICATION en la tabla (que le dice al servidor SQL que si el usuario que se conecta es el agente de replicación, espere que se suministre el valor de IDENTIDAD) ( prefiero el enfoque de replicación personalizado, ya que me da más flexibilidad )

mi. Modifique su procedimiento almacenado de replicación de inserción (generalmente denominado sp_MSins_CurrentTable) para insertar también utilizandoSET 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. Ahora puede reiniciar su agente de replicación.


1
jajaja, en comparación con el uso DBCC CHECKIDENT, este método es una gran cantidad de trabajo.
Jez

@Jez, deberá volver a crear la tabla (con IDENTITY) para ejecutar DBCC CHECKIDENT ... Una instantánea de la replicación creará la tabla sin la restricción IDENTITY (según su q, diría que ganó DBCC CHECKIDENT) 't trabajo)
Andrew Bickerton

FYI funcionó y la replicación crea la tabla con la restricción IDENTITY ...
Jez

@Jez, ¿qué tipo de replicación configuraste? (si lo configura como MERGE, eso sucederá, para TRANSACTIONAL generalmente no lo hace, aunque la replicación es altamente personalizable si no usa la GUI)
Andrew Bickerton

Transaccional. Como dije, la IDENTIDAD está ahí, pero el valor de identidad actual se restablece al valor inicial (1).
Jez
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.