我已在 SQL Server 2008 数据库中的几个表上启用了 CDC。我想更改可以保留更改历史记录的天数。
我读过,默认情况下更改日志会保留 3 天,然后由 sys.sp_cdc_cleanup_change_table 存储过程删除。
有谁知道如何更改此默认值,以便我可以保留日志更长时间。
谢谢
您需要更新数据库的 cdc_jobs.retention 字段。在至少为 CDC 启用一个表之前,cdc_jobs 表中的记录不会存在。
-- modify msdb.dbo.cdc_jobs.retention value (in minutes) to be the length of time to keep change-tracked data
update
j
set
[retention] = 3679200 -- 7 years
from
sys.databases d
inner join
msdb.dbo.cdc_jobs j
on j.database_id = d.database_id
and j.job_type = 'cleanup'
and d.name = '<Database Name, sysname, DatabaseName>';
将
<Database Name, sysname, DatabaseName>
替换为您的数据库名称。
两种替代解决方案:
放弃清理工作:
EXEC sys.sp_cdc_drop_job @job_type = N'cleanup';
通过 sp 更改工作:
EXEC sys.sp_cdc_change_job
@job_type = N'cleanup',
@retention = 2880;
保留时间以分钟为单位,最长 52494800(100 年)。但是,如果您放弃作业,则数据永远不会被清理,如果有数据需要清理,作业甚至不会查找。如果想无限期地保留数据,我宁愿放弃这份工作。
顺便说一句:如果您配置了 AlwaysOn 可用性组,则必须记住在故障转移后更新新主节点上的 CDC 配置! 在将保留期更新为比默认 3 天更长的值后,我们经历了惨痛的教训,在故障转移后我们丢失了这些更改!
或者,您可以通过比较 PRIMARY/SECONDARY 配置值,然后直接在辅助服务器上更新 msdb.dbo.cdc_jobs 来匹配,从而主动更新 SECONDARY 服务器。我不知道 Microsoft 是否正式支持这一点,但他们也不阻止直接更新 msdb 表。
以下是一个示例脚本,您可以在 AlwaysON 组中的副本上进行安排。它将检查主服务器上的当前配置并将更改同步到辅助服务器...
SET NOCOUNT ON
--We assume if this is the primary for even ONE database, then don't run
IF NOT EXISTS(
SELECT name,is_cdc_enabled,
sys.fn_hadr_is_primary_replica ( name) as IsPrimary
FROM sys.databases
WHERE is_cdc_enabled=1
AND sys.fn_hadr_is_primary_replica ( name) =1
)
BEGIN
DECLARE @Listener sysname
DECLARE @PrimaryConnectString VARCHAR(1000)
DECLARE @OPENROWSETString VARCHAR(4000)
--We just need to get ONE ListenerName to connect to the PRIMARY.
SET @Listener=(SELECT TOP 1 dns_name from sys.availability_group_listeners GL
join sys.availability_group_listener_ip_addresses LIP
on GL.listener_id = LIP.listener_id)
SET @PrimaryConnectString='Server='+@Listener+';Database=msdb;TrustServerCertificate=Yes;Trusted_Connection=Yes;MultiSubnetFailover=Yes;'
SELECT @PrimaryConnectString
SET @OPENROWSETString='
SELECT *
FROM OPENROWSET(
''SQLNCLI'',
'''+@PrimaryConnectString+''',
''IF EXISTS (SELECT 1 FROM msdb.dbo.cdc_jobs) SELECT
@@Servername as ServerName,
sd.name as DBName,
cdc.database_id,
cdc.job_type,
cdc.job_id,
cdc.maxtrans,
cdc.maxscans,
cdc.continuous,
cdc.pollinginterval,
cdc.retention,
cdc.threshold
FROM msdb.dbo.cdc_jobs cdc
JOIN sys.databases sd
ON cdc.database_id=sd.database_id''
)'
DROP TABLE IF EXISTS #RemoteConfig
CREATE TABLE #RemoteConfig (
ServerName varchar(64),
DBName varchar(64),
database_id int,
job_type varchar(12),
job_id uniqueidentifier,
maxtrans int,
maxscans int,
continuous bit,
pollinginterval int,
retention int,
threshold int
)
INSERT INTO #RemoteConfig
EXEC (@OPENROWSETString);
DROP TABLE IF EXISTS #LocalConfig
IF EXISTS (SELECT 1 FROM msdb.dbo.cdc_jobs)
SELECT
@@Servername as ServerName,
sd.name as DBName,
cdc.database_id,
cdc.job_type,
cdc.job_id,
cdc.maxtrans,
cdc.maxscans,
cdc.continuous,
cdc.pollinginterval,
cdc.retention,
cdc.threshold
INTO #LocalConfig
FROM msdb.dbo.cdc_jobs cdc
JOIN sys.databases sd
ON cdc.database_id=sd.database_id
--DEBUG
SELECT 'PRIMARY'as Role,* FROM #RemoteConfig
SELECT 'SECONDARY' as [Role],* FROM #LocalConfig
--Will update if there are any unmatching column values for each job type and db
UPDATE l
SET l.maxtrans=r.maxtrans,
l.maxscans=r.maxscans,
l.continuous=r.continuous,
l.pollinginterval=r.pollinginterval,
l.retention=r.retention,
l.threshold=r.threshold
FROM msdb.dbo.cdc_jobs as l
JOIN #RemoteConfig r
ON db_name(l.database_id) = r.DBname
AND l.job_type = r.job_type
WHERE
r.maxtrans <> l.maxtrans OR
r.maxscans <> l.maxscans OR
r.continuous <> l.continuous OR
r.pollinginterval <> l.pollinginterval OR
r.retention <> l.retention OR
r.threshold <> l.threshold
IF @@ROWCOUNT > 0 PRINT '***CHANGES SYNCHED***' ELSE PRINT '***NO CHANGES***'
SELECT db_name(msdb.dbo.cdc_jobs.database_id) as DBName, * FROM msdb.dbo.cdc_jobs
END
ELSE
BEGIN
PRINT '***PRIMARY REPLICA, SKIPPING CONFIG SYNC***'
SELECT db_name(msdb.dbo.cdc_jobs.database_id) as DBName, * FROM msdb.dbo.cdc_jobs
END