徵狀
比較時於記憶體 SYSCOMMITTABLE 和 Microsoft SQL Server 中的磁碟上的 sys.syscommittab 檔案,您可能會看到重複的索引鍵資料列。這些重複的值可能會造成備份和檢查點作業失敗。
「 無法插入重複的索引鍵資料列,在物件 'sys.syscommittab' 'si_xdes_id' 的唯一索引。重複的索引鍵值是 (KeyValue)。
錯誤: 3999,高的嚴重性等級: 17,狀態: 1。
無法排清到磁碟中因為錯誤 2601 dbid DatabaseID的認可資料表。檢查錯誤記錄檔,如需詳細資訊 >。
原因
之所以發生這個問題,是因為 SQL Server 變更追蹤已知的問題。
解決方案
若要解決導致重複的索引鍵的因素,將套用下列修正程式中,視您的情況: 修正: 在 SQL Server 2008年或 SQL Server 2008 R2 的資料庫上的備份作業失敗時,如果您啟用這個資料庫http://support.microsoft.com/kb/2522893修正程式的歷程: 備份失敗 SQL Server 2008年、 SQL Server 2008 R2 或 SQL Server 2012年中,如果您啟用變更追蹤上資料庫http://support.microsoft.com/kb/2603910修正程式: SQL Server 2008年中的備份作業失敗SQL Server 2008 R2 或啟用變更追蹤http://support.microsoft.com/kb/2682488,雖然這些修正程式會導致重複的索引鍵資料列無法繼續出現,它們並不會自動移除重複的資料列後,SQL Server 2012年資料庫。而不要移除重複的資料列受影響的資料庫不能完成資料庫檢查點,且備份可能會失敗。若要移除重複的資料列,請使用下列方法之一。
方法 1: 停用及啟用變更追蹤
-
停用追蹤受影響的資料表與資料庫的變更。
-
發出手動進行資料庫檢查點。
-
啟用 [追蹤] 將受影響的資料庫和資料表的變更。
如需有關變更追蹤的詳細資訊,請參閱啟用和停用變更追蹤。如需有關如何發出手動檢查點的資訊,請參閱檢查點 (考慮改用 SQL)
方法 2: 以手動方式刪除重複的資料列
-
將在 < 解決方案=""> 一節結尾處的考慮改用 SQL 指令碼複製到文字編輯器。
-
找出的 < AFFECTED_DB > 版面配置區中的指令碼,並取代受影響的資料庫名稱。
-
將儲存修改過的指令碼到您的硬碟為.sql 檔案。例如:
C:\temp\remove_duplicates.sql
如果您執行 SQL Server 2014年,您必須授與每個服務的 SID 完全控制的 mssqlsystemresource.ldf 和 mssqlsystemresource.mdf 的檔案。若要這麼做,請依照下列步驟執行:
-
巡覽至 Binn 目錄對應到您的執行個體識別碼。例如:
C:\Program 必要 SQL Server\ < 執行個體識別碼 > \MSSQL\Binn
-
開啟 mssqlsystemresource.ldf 和 mssqlsystemresource.mdf 的屬性,然後按一下 [安全性] 索引標籤。
-
找出 SQL Server 服務每個服務 SID,並請注意預設權限:
* 讀取 & 執行
*Read
-
授與 SQL Server 服務每個服務 SID 完全控制],,然後關閉 [權限] 對話方塊。
-
在單一使用者模式中啟動 SQL Server。如需詳細資訊,請參閱在單一使用者模式中啟動 SQL Server。
-
連線到 SQL Server 專用的系統管理員連線 (DAC) 下使用sqlcmd命令列。例如:
sqlcmd-S PRODSERV1\MSSQLSERVER-A-E-i c:\temp\remove_duplicates.sql然後,執行修改過的考慮改用 SQL 指令碼。
-
在多使用者模式中,啟動 SQL Server,然後確認備份與對受影響的資料庫的檢查點作業順利完成。如果使用步驟 4,將還原成預設值的權限。
交易 SQL 指令碼
--Create a temporary database to store the necessary rows required to remove the duplicate dataif exists(select 1 from sys.databases where name = 'dbChangeTrackingMetadata')begindrop database dbChangeTrackingMetadataendgocreate database dbChangeTrackingMetadatago --Table to store the contents of the SYSCOMMITTABLEuse dbChangeTrackingMetadatagocreate 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 tablecreate 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 OPENROWSETexec sys.sp_setbuildresource 1go --Change <AFFECTED_DB> to the database that contains the duplicate valuesUSE <AFFECTED DB>godeclare @rowcount bigintSET @rowcount = 0 --Copy all rows from the SYSCOMMITTABLE into the temporary databaseinsert into dbChangeTrackingMetadata.dbo.t_SYSCOMMITTABLESELECT commit_ts, xdes_id, commit_lbn, commit_csn, commit_timeFROM OpenRowset (table SYSCOMMITTABLE, db_id (), 0, 0) --Save the duplicate values into the temporary databaseinsert into dbChangeTrackingMetadata.dbo.t_syscommittabselect ondisk_ct.* from sys.syscommittab as ondisk_ctjoin dbChangeTrackingMetadata.dbo.t_SYSCOMMITTABLE as inmem_cton ondisk_ct.xdes_id = inmem_ct.xdes_id --Delete the duplicate valuesdelete from sys.syscommittabwhere xdes_id in ( select xdes_id from dbChangeTrackingMetadata.dbo.t_syscommittab )set @rowcount = @@rowcountif (@rowcount > 0)beginprint ''print 'DELETED '+CAST(@rowcount as NVARCHAR(10))+' rows from sys.syscommittab that were also stored in SYSCOMMITTABLE'print ''endelsebeginprint ''print 'Failed to DELETE DUP rows from sys.syscommittab'print ''endexec sys.sp_setbuildresource 0go