Leer en inglés

Compartir a través de


Filas de clave duplicadas de la tabla sys.syscommittab en SQL Server

En este artículo se proporciona información sobre cómo resolver un problema de Seguimiento de cambios de SQL Server que puede dar lugar a filas duplicadas en sys.syscommittab el archivo.

Versión original del producto: SQL Server 2008 y las versiones posteriores
Número de KB original: 3083381

Síntomas

Al comparar el archivo en memoria SYSCOMMITTABLE y el archivo en disco sys.syscommittab en Microsoft SQL Server, es posible que vea filas de clave duplicadas. Estos valores duplicados pueden provocar un error en las operaciones de copia de seguridad y punto de comprobación.

"No se puede insertar una fila de clave duplicada en el objeto "sys.syscommittab" con el índice único "si_xdes_id". El valor de clave duplicado es (KeyValue).
Error: 3999, Gravedad: 17, Estado: 1.
No se pudo vaciar la tabla de confirmación en el disco en dbidDatabaseID debido al error 2601. Compruebe el registro de errores para obtener más información".

Causa

Este problema se produce debido a un problema conocido en el seguimiento de cambios de SQL Server.

Resolución de factores que provocan las claves duplicadas

Para resolver los factores que provocan las claves duplicadas, aplique una de las siguientes correcciones, según corresponda para su situación:

Aunque estas correcciones impiden que las filas de clave duplicadas sigan apareciendo, no quitan automáticamente las filas duplicadas. Sin quitar las filas duplicadas, la base de datos afectada no puede completar los puntos de comprobación de la base de datos y es posible que se produzca un error en las copias de seguridad.

Deshabilitar y habilitar el seguimiento de cambios para quitar filas duplicadas

  1. Deshabilite el seguimiento de cambios en las tablas y bases de datos afectadas.
  2. Emita un punto de control de base de datos manual.
  3. Habilite el seguimiento de cambios en la base de datos y tablas afectadas.

Para obtener más información sobre el seguimiento de cambios, consulte Habilitación y deshabilitación del seguimiento de cambios. Para emitir un punto de control manual, consulte CHECKPOINT (Transact-SQL).

Eliminar manualmente las filas duplicadas

  1. Copie el script de Transact-SQL de la sección script de Transact-SQL en un editor de texto.
  2. Busque el <AFFECTED_DB> marcador de posición en el script y reemplácelo por el nombre de la base de datos afectada.
  3. Guarde el script modificado en el disco duro como un archivo .sql. Por ejemplo, C:\temp\remove_duplicates.sql.

Si usa SQL Server 2014 y versiones posteriores, debe conceder el control total del SID por servicio a los mssqlsystemresource.ldf archivos y mssqlsystemresource.mdf . Para ello, siga estos pasos:

  1. Vaya al directorio Bin que corresponde al identificador de instancia. Por ejemplo:
    C:\Program Files\Microsoft SQL Server\<Instance ID>\MSSQL\Binn

  2. Abra las propiedades de mssqlsystemresource.ldf y y mssqlsystemresource.mdf, a continuación, seleccione la pestaña Seguridad .

  3. Busque el SID de servicio por servicio de SQL Server y anote los permisos predeterminados:

    • *Read & execute
    • *Read
  4. Conceda el servicio SQL Server por sid de servicio control total y, a continuación, cierre los cuadros de diálogo de permisos.

  5. Inicie SQL Server en modo de usuario único. Para obtener más información, vea Iniciar SQL Server en modo de usuario único.

    Nota

    Cuando SQL Server se inicia en modo de usuario único, omite el proceso de inicio de las bases de datos que forman parte de un grupo de disponibilidad AlwaysOn (AG). Si necesita solucionar un problema con el seguimiento de cambios que requiere iniciar SQL Server en modo de usuario único y la base de datos con el seguimiento de cambios habilitado también forma parte de un grupo de disponibilidad, debe quitar la base de datos del grupo de disponibilidad antes de iniciar SQL Server en modo de usuario único para que la base de datos se conecte.

  6. Use una sqlcmd línea de comandos para conectarse a SQL Server en la conexión de administrador dedicada (DAC) y ejecute el script transact-SQL modificado. Por ejemplo:

    Consola
    sqlcmd -S PRODSERV1\MSSQLSERVER -A -E -i c:\temp\remove_duplicates.sql
    
  7. Reinicie SQL Server en modo multiusuario y compruebe que las operaciones de copia de seguridad y CHECKPOINT en la base de datos afectada se completen correctamente. Si se usó el paso 4, revierta los permisos a los valores predeterminados.

Script de Transact-SQL

SQL
--Create a temporary database to store the necessary rows required to remove the duplicate data 
USE master
GO
IF EXISTS(SELECT 1 FROM sys.databases WHERE name = 'dbChangeTrackingMetadata')
BEGIN
  DROP DATABASE dbChangeTrackingMetadata
END
GO
CREATE DATABASE dbChangeTrackingMetadata
GO

--Table to store the contents of the SYSCOMMITTABLE
USE dbChangeTrackingMetadata
GO
CREATE TABLE dbo.t_SYSCOMMITTABLE (
commit_ts BIGINT
,xdes_id BIGINT
,commit_lbn BIGINT
,commit_csn BIGINT
,commit_time DATETIME
)
GO

--Table to store the duplicate rows to be removed from the sys.syscommittab table

CREATE TABLE dbo.t_syscommittab (
commit_ts BIGINT
,xdes_id BIGINT
,commit_lbn BIGINT
,commit_csn BIGINT
,commit_time DATETIME
,dbfragid INT
)
GO

--Enable the usage of OPENROWSET
EXEC sys.sp_setbuildresource 1
GO

--Change <AFFECTED_DB> to the database that contains the duplicate values
USE <AFFECTED DB>
GO
DECLARE @rowcount BIGINT
SET @rowcount = 0

--Copy all rows from the SYSCOMMITTABLE INTo the temporary database
INSERT INTO dbChangeTrackingMetadata.dbo.t_SYSCOMMITTABLE
SELECT commit_ts, xdes_id, commit_lbn, commit_csn, commit_time
FROM OPENROWSET (table SYSCOMMITTABLE, db_id (), 0, 0)

--Save the duplicate values INTo the temporary database
INSERT INTO dbChangeTrackingMetadata.dbo.t_syscommittab
SELECT ondisk_ct.* 
FROM sys.syscommittab as ondisk_ct
JOIN dbChangeTrackingMetadata.dbo.t_SYSCOMMITTABLE as inmem_ct
 ON ondisk_ct.xdes_id = inmem_ct.xdes_id

--Delete the duplicate values
DELETE FROM sys.syscommittab
WHERE xdes_id in ( SELECT xdes_id from dbChangeTrackingMetadata.dbo.t_syscommittab )

SET @rowcount = @@rowcount

IF (@rowcount > 0)
BEGIN
  PRINT ''
  PRINT 'DELETED '+CAST(@rowcount as NVARCHAR(10))+' rows from sys.syscommittab that were also stored in SYSCOMMITTABLE'
PRINT ''
END
ELSE
BEGIN
  PRINT ''
  PRINT 'Failed to DELETE DUP rows from sys.syscommittab'
  PRINT ''
END
EXEC sys.sp_setbuildresource 0
GO