简介:SQL Server 2000 数据库同步与复制配置讲解文档,面向需要在多个 SQL Server 2000 实例间保持一致数据库结构的 DBA、运维与开发人员。文档围绕发布-订阅复制机制,先梳理六项准备:创建同名 Windows 用户、设置共享快照目录、调整 SQLSERVERAGENT 启动账户、启用 SQL Server 和 Windows 混合身份验证、互注册对方服务器、为纯 IP 环境配置服务器别名;再说明配置分发服务器、创建事务发布或合并发布、添加订阅服务器的流程,并标出快照权限、distributor_admin 密码、发布表需带主键等易错点。压缩包内为单个 PDF 文件,约 114KB,步骤清晰、可对照逐步实施。已有 855 人学习。
1. 为什么 SQL Server 2000 数据库同步是一件绕不开的工作
sqlserver 2000 数据库同步,说白了就是把一台老库里的表持续搬进另一台 SQL Server 2000,既要不丢数据,又不能在搬运时把正在跑业务的源表锁死。这个场景在今天的生产环境里依然真实存在:MES、计量、财务这类老系统被业务一直养着,配套应用只认 SQL Server 2000,可报表库、容灾库、测试库又都指着同一份数据,这就是数据库同步问题的起点。它适合三类人:接手维护老系统的新人,给老库做容灾或迁移的 DBA,以及需要在两个 2000 实例之间做读写分离的架构师。这里真正要解决的,不是“换成新数据库”的规划问题,而是把同步链路做成可靠、可验证、出了故障能在半小时内恢复的工程。
2. SQL Server 2000 同步路线:先按实时性、冲突、成本做完选型
2.1 事务复制是原生方案里唯一接近实时的选项
事务复制(Transactional Replication)是 SQL Server 2000 原生同步方案里能力最强的一种。它的工作模型是:发布服务器上有一个 Log Reader 进程持续扫描事务日志,把发布表中被标记为复制的变更解析成命令,写入分发数据库(Distribution);订阅服务器再从分发服务器拉取这些命令,在目标库上重放。整个过程对业务系统透明,应用层完全感知不到同步存在。
这种方案适合两种典型场景。一是生产库和报表库之间做近实时只读副本,延迟通常在秒级到十几秒。二是作为灾备的数据层补充,在日志传送尚不可用或不想恢复整个库时,事务复制能保证主库的增量在目标端持续落库。实际部署里需要注意,发布表必须有主键。主键不只是建索引用的,后续 UPDATE 和 DELETE 都要靠它在订阅端定位行。没有主键的表在 2000 的发布向导里根本加不进去,强行用 sp_addarticle 也会报错。
还要明确一个边界:事务复制默认是单向的,主库写、订阅库只读。如果想双向同步得用合并复制(Merge Replication),但 2000 的合并复制在冲突检测和优先级配置上非常繁琐,生产库一旦并发写冲突,处理代价远超省下的那一台机器成本。我对事务复制的定位是默认第一选择,只有当目标端版本差太多、或者连分发服务器权限都拿不到时,才退到第 4 章的 DTS 路线。
2.2 DTS 与链接服务器:适合按批同步而不是实时事件
DTS(Data Transformation Services)是 SQL Server 2000 时代的官方数据搬运工具,在 2005 里被 SSIS 取代。DTS 包可以定义数据源、目标、转换规则和任务流,可以手动跑,也能由 SQL Agent 作业定时触发。相比事务复制,DTS 不解析事务日志,它是一段时间内对源库做查询拉取,对源库的压力是突发的,适合离线批量同步。
另一个配合组件是链接服务器(Linked Server)。它让一条 T-SQL 能直接跨实例访问对象,典型写法是 SELECT * FROM [SYNC_TARGET].[erp].dbo.orders,把远程表当本地表一样读。DTS 包里的“执行 SQL 任务”配合链接服务器写同步逻辑,是老库之间最灵活的增量同步姿势。
DTS + 链接服务器的短板很明确:没有自动断点、没有命令冲突检测、跨实例写操作还要依赖 MSDTC。网络一抖动,批处理跑到一半失败,下次再跑就可能重复 UPDATE 或漏掉一批数据。所以我会在目标表上建联合主键,同步脚本里用“先 UPDATE 后 INSERT + 目标表不存在才插入”的写法,把幂等性先兜住。这套脚本放在第 4 章,可以直接抄作业。
2.3 日志传送:整个库的一致副本,不是表的同步
日志传送(Log Shipping)在 SQL Server 2000 企业版里提供。原理是定期备份主库的事务日志文件,传输到目标服务器,目标服务器按顺序恢复(RESTORE WITH NORECOVERY 或 STANDBY)。它同步的粒度是“整个数据库”,而不是某几张表,目标实例最终得到的是一个完整、处于恢复状态的一致性副本。
日志传送的实时性取决于日志备份间隔,常见做法是五分钟到十五分钟做一次日志备份。目标库在 STANDBY 模式下可以只读查询,但不能写。它适合需要完整库做报表、或者做容灾演练的团队,但没法单独同步两张表——附带整个库意味着日志文件越来越多,恢复链越拉越长,中间任何一份日志文件损坏就得重启整条链。
选型时经常有人纠结:一个库里十张表,业务上只关心其中两张表的变化,却想配日志传送。这是典型的方案错配。表级同步用事务复制,库级容灾用日志传送,别混着用。如果连企业版都没有,日志传送直接不用考虑。
2.4 选型对照:延迟、冲突、初始化、版本要求
| 方案 | 同步粒度 | 延迟 | 目标端可写 | 初始化方式 | 版本要求 |
|---|---|---|---|---|---|
| 事务复制 | 表级 | 秒级到十几秒 | 不可写(单向) | 快照或备份 | 发布端需标准版 |
| DTS+链接服务器 | 自定义 SQL | 分钟级到小时级 | 可以 | 自行编写 | 所有版本 |
| 日志传送 | 整个库 | 分钟级 | 只读 | 全备+日志链 | 仅企业版 |
| 备份还原 | 整个库 | 小时级 | 可读可写 | 全备+差异 | 所有版本 |
补充一个经验:市面上各种数据库同步软件/数据库同步工具看上去安装快、配置简单,但对 SQL Server 2000 这种老实例,驱动和兼容性往往比原生方案更折腾。同步工具大多按 2005 以后的机制设计,对 2000 的 SQLOLEDB 连接方式、timestamp 列行为、隐式事务处理都可能水土不服。原生方案能跑通的,我一般不动工具,因为工具的坑比原生知识点更难在搜索引擎里找到答案。
3. 用事务复制跑通两个 SQL Server 2000 库:配置命令与参数
3.1 同步前检查:版本权限、网络连通、目标库准备
配置发布之前,先确认两端环境是健康的。在源库和目标库各执行一次:
SELECT @@VERSION AS ver, SERVERPROPERTY('Edition') AS edition, SERVERPROPERTY('IsClustered') AS is_cluster逻辑说明:这条语句分别返回版本号、版本类型(企业版/标准版)、是否集群实例。SQL Server 2000 的标准版可以当发布服务器做事务复制,但日志传送必须企业版,这一步先确认版本能省掉后续不少弯路。参数说明:SERVERPROPERTY('Edition') 返回的字符串要能区分标准版和企业版,如果显示 Developer 或 Evaluation 也要意识到功能限制。
网络连通性上,SQL Server 2000 默认实例监听 1433 端口,命名实例依赖 SQL Browser 服务。命令行验证方式就是 telnet 目标 IP 1433,看能否连上端口。这一步容易被忽略,但偏偏是复制作业最常翻车的点:SQL Agent 服务没启动。Log Reader 进程和分发进程都由 SQL Agent 拉起,SQL Agent 一停,复制就卡在“未启动”状态,数据完全不动。所以配置前我习惯先看一遍服务管理器里的 SQL Agent 状态。
版本补丁方面,源和目标如果都跑 SQL Server 2000,尽量都装到 Service Pack 4。2000 早期版本的复制有大量和日志读取相关的 bug,很多在 SP4 里才修掉,裸奔版本配复制就是给自己挖坑。
3.2 配置分发与发布:sp_adddistributiondb 别用默认保留期
分发服务器可以和发布服务器放在同一台机器上。在源库执行下面的命令:
exec sp_adddistributor @distributor = N'source01', @password = N'' exec sp_adddistributiondb @database = N'distribution', @data_folder = N'D:\MSSQL\Data', @log_folder = N'D:\MSSQL\Log', @max_distretention = 96, @history_retention = 48逻辑说明:第一句把当前实例配置成分发服务器;第二句创建分发数据库,所有等待分发的复制命令都会先写进这里。参数说明里最值得关注的是 @max_distretention,它的单位是小时,控制已分发命令在分发库里保留多久,常见默认值是 72 小时。我改成 96 是给周末停机留一点余量——一旦订阅端离线超过这个窗口,订阅就过期,后面第 5 章会专门讲到这个坑。@data_folder 和 @log_folder 指向分发数据库的数据和日志目录,要确认磁盘空间足够,复制积压时这里涨得很快。
然后创建发布:
exec sp_addpublication @publication = N'pub_erp', @repl_freq = N'continuous', @status = N'active', @sync_method = N'concurrent', @retention = 0, @immediate_sync = N'false' exec sp_addarticle @publication = N'pub_erp', @article = N'orders', @source_object = N'orders', @destination_object = N'orders', @type = N'logbased'逻辑说明:sp_addpublication 定义发布属性,sp_addarticle 把源库里的 orders 表加为发布项。参数说明:@repl_freq 用 continuous 表示持续从日志采集变更;@sync_method 用 concurrent 表示生成初始快照时尽量不长时间锁表,这是 2000 里对在线业务最友好的方式;@type='logbased' 明确这是一张事务复制类型的表。发布表必须有主键,没有主键 sp_addarticle 会直接报错,先在源表上补主键再回来加文章。
3.3 创建订阅并初始化快照:concurrent 模式避免锁表
创建订阅最可靠的方式是在企业管理器里跑创建订阅向导,向导最后一步可以选择生成 SQL 脚本。这里给一段最简化的命令行写法,方便理解底层动作:
exec sp_addsubscription @publication = N'pub_erp', @subscriber = N'db02', @destination_db = N'erp_report', @sync_type = N'automatic', @subscription_type = N'push' exec sp_addpushsubscription_agent @publication = N'pub_erp', @subscriber = N'db02', @subscriber_db = N'erp_report', @subscriber_login = N'sa', @subscriber_password = N'YourPwd', @frequency_type = 0x10逻辑说明:sp_addsubscription 在订阅库注册订阅,sp_addpushsubscription_agent 创建负责推送的调度进程。参数说明:@sync_type='automatic' 表示订阅创建后自动生成并应用初始快照;@subscription_type='push' 表示推订阅,分发服务器主动把数据推给订阅端;@frequency_type=0x10 在 2000 里表示连续运行。我一般选推订阅而不是拉订阅,因为分发进程跑在分发服务器上,账号密码统一收口,排查问题时只需要盯一台机器。
订阅服务器上不要预建同名表。快照会自动建表建索引,预建的表如果结构不完全一致,快照应用阶段会报对象已存在或列不匹配。如果因为某种原因必须预建表,那就要保证结构、主键名、索引全部一致,这是一条性价比很低的路径。
提示:事务复制初始化期间,源库业务不能停。concurrent 快照生成完后,Log Reader 会把快照生成期间产生的事务变更补送给订阅端,所以订阅端数据完整一致的时间点要等增量追平,不是快照应用完就立刻一致。
3.4 确认同步状态:从 sysprocesses 和分发历史表看复制
配完之后第一件事,是确认快照真的应用完、增量已经追平。在分发服务器上执行:
SELECT spid, program_name, status, last_batch FROM master.dbo.sysprocesses WHERE program_name LIKE '%Replication%'逻辑说明:这条 SQL 能列出所有属于复制系统的后台进程。参数说明:program_name 里带 Replication 字样的就是 Log Reader 或分发进程;status 如果是 sleeping 或 runnable 都算正常,last_batch 显示最后一批命令执行时间。如果 last_batch 停留在几小时前,说明复制卡了,不要犹豫,马上进下一步查分发历史。
再查分发数据库的历史记录:
SELECT TOP 20 [time], [comments], [error_id] FROM distribution.dbo.MSdistribution_history ORDER BY [time] DESC正常时 error_id 为 0,comments 里能看到类似成功投递的记录。error_id 非 0 就要看具体错误码,常见的是订阅过期或者网络超时。快照是否应用完成,直接去订阅库看:
SELECT COUNT(*) FROM erp_report.dbo.orders如果表已经建出来、行数和源库逐步接近,说明快照和增量追赶都正常。刚配完复制时订阅端有一点延迟是正常的,Log Reader 需要把快照时间点到当前时刻的日志命令积压全部补上,先等几分钟观察 last_batch 往前走,不要一看到延迟就重启服务。复制这种老黑匣子,最忌乱动,动之前先看状态。
4. 用链接服务器 + DTS 做增量同步:没有复制权限时的后备方案
4.1 建立链接服务器:SQLOLEDB 与 MSDASQL 的坑
拿不到分发服务器权限、或者目标端是 2005 以上版本的异构场景,链接服务器是常用后备。在源库执行:
exec sp_addlinkedserver @server = N'SYNC_TARGET', @srvproduct = N'SqlServer2000', @provider = N'SQLOLEDB', @datasrc = N'192.168.1.20' exec sp_addlinkedsrvlogin @rmtsrvname = N'SYNC_TARGET', @useself = N'False', @rmtuser = N'sa', @rmtpassword = N'YourPwd'逻辑说明:第一段注册远程服务器,第二段配置本地登录到远程服务器的账号映射。参数说明:@provider 必须写 SQLOLEDB,这是 2000 自带的 OLEDB 提供程序。如果把 @provider 留空,2000 可能走系统默认的 MSDASQL,也就是把 OLEDB 转成 ODBC,性能和错误提示都会变得不可控。@datasrc 填目标服务器的 IP 或机器名;命名实例可以填 IP\实例名,但要确保 SQL Browser 服务和 UDP 1434 端口是通的。
建完连接先用最轻的查询验证连通性:
SELECT TOP 1 name FROM [SYNC_TARGET].erp.dbo.sysobjects能返回对象名,链接服务器就通了。如果报“OLE DB 提供程序 'SQLOLEDB' 无法启动分布式事务”,这是 MSDTC 没就绪。跨实例写操作依赖分布式事务协调器,需要在控制面板的组件服务里把 Distributed Transaction Coordinator 设为自动启动,并允许入站和出站网络事务。排查 MSDTC 是这条路线里最常见的体力活,但确认一次后面就顺了。
注意:链接服务器能读不意味着能写。跨实例 UPDATE/INSERT 会强制启用分布式事务,MSDTC 服务一旦停止,要么同步任务失败,要么数据写一半两边不一致。正式跑批之前,先手动执行一条跨实例 INSERT 验证整个事务链。
4.2 用时间戳列做增量同步:UPDATE 后 INSERT 的两步脚本
业务表有更新时间列时,可以在存储过程或 DTS 的 SQL 任务里写增量同步脚本:
BEGIN TRAN UPDATE t SET t.status = s.status, t.modtime = s.modtime FROM [SYNC_TARGET].erp.dbo.orders t JOIN erp.dbo.orders s ON t.order_id = s.order_id WHERE s.modtime > @last_sync_time INSERT INTO [SYNC_TARGET].erp.dbo.orders (order_id, status, modtime) SELECT s.order_id, s.status, s.modtime FROM erp.dbo.orders s WHERE s.modtime > @last_sync_time AND NOT EXISTS ( SELECT 1 FROM [SYNC_TARGET].erp.dbo.orders t WHERE t.order_id = s.order_id ) COMMIT逻辑说明:第一步把两边都有、但源库更新过的行刷到目标表;第二步把源库有、目标表没有的行插进去。UPDATE 语句里 FROM...JOIN 的写法是 SQL Server 2000 支持的扩展语法,配合链接服务器可以跨实例更新。参数说明:@last_sync_time 不是“当前时间减去多少分钟”,而是上一次同步完成时刻。实际操作时我会建一张 sync_log 表记录每次同步的结束时间,下次同步开始时把上次结束时间取出来作为 @last_sync_time,这样即使断点续跑也能增量补齐。
目标表务必有主键或唯一索引,否则 UPDATE 会变成全表定位,远程表扫描会慢到你想砸键盘。同步频率不建议低于一分钟一次,因为每次跑批都有事务日志开销,15 分钟一次是兼顾延迟和开销的常用起点。
4.3 把 DTS 包挂到 SQL Agent 作业上:dtsrun 命令与调度参数
如果同步逻辑已经在 DTS 包里,用 dtsrun 命令行运行包,再挂到 SQL Agent 作业上做定时调度。dtsrun 的标准命令如下:
dtsrun /S source01 /U sa /P YourPwd /N MySync /M逻辑说明:/S 指定 DTS 包所在服务器,/U 和 /P 是登录服务器的账号,/N 指定包名,/M 表示使用包的保护密码而不是命令行明文。参数说明:如果包内部的任务使用链接服务器访问远端库,那 dtsrun 触发的是同一个分布式事务链,MSDTC 仍然是前提。
创建 SQL Agent 作业调度这条命令:
exec msdb.dbo.sp_add_job @job_name = N'SyncOrdersJob', @enabled = 1 exec msdb.dbo.sp_add_jobstep @job_name = N'SyncOrdersJob', @step_name = N'RunDts', @subsystem = N'CmdExec', @command = N'dtsrun /S source01 /U sa /P YourPwd /N MySync /M' exec msdb.dbo.sp_add_jobschedule @job_name = N'SyncOrdersJob', @name = N'Every15Min', @freq_type = 4, @freq_interval = 1, @freq_subday_type = 4, @freq_subday_interval = 15逻辑说明:先建作业,再建命令行步骤,最后配置每 15 分钟执行一次的调度计划。参数说明:@subsystem='CmdExec' 表示步骤调用操作系统命令,而不是 T-SQL;@freq_type=4 表示每天类型的计划,@freq_interval=1 表示每天都执行,@freq_subday_type=4 表示按分钟间隔,@freq_subday_interval=15 表示 15 分钟跑一次。这里最容易踩的坑是权限:CmdExec 步骤运行时用的是 SQL Agent 服务账号,这个账号必须对源库和链接服务器都有访问权限,否则作业里报的错跟你手动跑 dtsrun 的报错完全不一样。
4.4 没有更新时间列时的兜底:触发器与整表比对
不是每张表都有 modtime。没有增量字段时,我一般在这两个方案里选:
一是给源表加一张增量日志表,在源表上挂 UPDATE 和 INSERT 触发器,把主键、操作时间、操作类型写进日志表。同步作业只读日志表,再用主键回源表取当前值。代价是源表每次更新多一次触发器的写开销,但这在 2000 上是可以接受的。触发器建议用 NOT FOR REPLICATION 选项,避免在复制链路里再触发连锁动作。
二是整表主键差集比对。数据量小时可以用链接服务器直接把两边主键拉出来做差:
SELECT s.order_id FROM erp.dbo.orders s LEFT JOIN [SYNC_TARGET].erp.dbo.orders t ON s.order_id = t.order_id WHERE t.order_id IS NULL UNION ALL SELECT t.order_id FROM [SYNC_TARGET].erp.dbo.orders t LEFT JOIN erp.dbo.orders s ON s.order_id = t.order_id WHERE s.order_id IS NULL逻辑说明:第一段查源库有而目标库没有的 ID,第二段查目标库有而源库没有的 ID,两边合并就是全部需要补齐和需要删除的行。参数说明:这个写法只在表不大的时候可用,超过百万行就会把整表主键在网络上全传一遍。实际使用时我会加时间条件分页,比如按 order_date 分段,每次比较一个月的量。把整表比对当默认方案,在老机器上会把性能拖到不可收拾。
5. 老库同步的翻车现场:五个排查点与血泪参数
5.1 快照初始化期间发布库被锁死
现象:配置好发布订阅,启动初始快照后,业务系统在源库的写操作大面积阻塞,页面超时,并发高的表直接卡死。
原因:默认快照方式是用 bcp 生成数据,bcp 在 SQL Server 2000 上默认给表加共享锁,大表生成快照期间业务写事务进不来。业务表数据量越大,锁表窗口越长。
解决:把发布属性里的同步方式改成并发快照,也就是 sp_addpublication 的 @sync_method='concurrent'。并发模式下快照进程不再长期持有表级锁,快照期间产生的新变更由 Log Reader 进程补送到订阅端。这个模式的代价是初始化完成后订阅端要等增量补齐才能视为一致。如果业务表大到连并发快照都扛不住,另一个可行路径是先从备份还原订阅库,再把复制初始化方式设为“从备份”,这是 2000 复制支持的一种初始化方式,但要求两端 schema 完全一致。我个人的习惯还是错峰:选业务低谷期生成快照,同时把分发保留期先调大,比硬上复杂配置更省心。
5.2 订阅离线超过保留期,分发进程罢工
现象:订阅服务器故障停机四天,恢复后复制一直提示订阅已过期。日志读取正常,但数据就是不往订阅端走,手动启动订阅进程也被拒绝。
原因:分发库的 @max_distretention 常见默认值是 72 小时。订阅端超过这个时间没有来拉取命令,分发服务器就判定订阅失效,历史命令直接标记为过期。
解决:已经过期的订阅不要试图把积压命令磨回来,重新初始化订阅是唯一可靠的恢复路径。在复制监视器里对右侧订阅右键选择重新初始化订阅,或者重建订阅并把 @sync_type 设成 automatic。预防办法是配置分发库时把 @max_distretention 调到 168(一周),给停机维护留够窗口。这个坑的教训是:复制配好后,分发保留期要在第一时间按业务允许的最大停机时长去设置,默认值只适合从不出故障的理想环境。
5.3 两边排序规则不一致导致同步中文乱码
现象:同步过去的中文全部显示成问号,或者一条带中文等值条件的查询在源库正常,在目标库查不到数据。
原因:源库和目标库的排序规则(Collation)不一致。源库是 Chinese_PRC_CI_AS,目标库是 SQL_Latin1_General_CP1_CI_AS,字符存储和比较方式完全不同,中文自然乱套。
解决:统一目标库排序规则。新建库时显式指定:
CREATE DATABASE erp_report COLLATE Chinese_PRC_CI_AS逻辑说明:这条命令在建库阶段把排序规则固定为简体中文、不区分大小写。参数说明:Chinese_PRC_CI_AS 里的 CI 表示 case-insensitive,AS 表示 accent-sensitive,这是中文环境最常见的组合。已经存在的库要确认规则,可以用这条查询:
SELECT name, collation FROM master.dbo.sysdatabases结果里如果源和目标不一致,最稳妥的做法是重建目标库并重新灌数据,不要在列级别 COLLATE 上做修补,那样会让索引失效,后续性能问题更麻烦。已经有乱码数据的表,清掉重灌比逐行修补快得多。
5.4 DTS 批量更新把事务日志撑爆
现象:用 DTS 跑一张几百万行的表,源库的 LDF 文件在十几分钟内暴涨,最终磁盘塞满,数据库进入可疑或只读状态。
原因:DTS 的数据转换任务默认把整个步骤包裹在一个大事务里,或者包属性里勾选了“每个任务作为一个事务”。几百万行的批量写入持有一个超长事务,日志文件无法截断,只能一直膨胀。
解决:两条出路。一是改用 bcp 分批导入导出,bcp 自带批大小参数:
bcp source01.erp.dbo.orders out orders.bcp -S source01 -U sa -P YourPwd -c -b 10000-b 10000 表示每批 10000 行提交一次,导入时同样加 -b 参数。使用 -c 字符格式适合普通业务表,如果有大字段或二进制类型就用 -n 原生格式,但 -n 只适用于两端都是 SQL Server 的场景。中文环境要加 -C 936 指定代码页,否则导入端又是一轮乱码。二是把 SQL 任务里的搬运脚本改成循环分页,每次只处理一万行,并在循环体内显式 checkpoint。DTS 包里有关事务提交的设置,优先选“按批提交”,不要选“一个任务一个事务”。
5.5 复制进程空转,状态 running 但数据不走
现象:复制监视器里订阅状态一直显示运行中,但查订阅表行数半天不变,Log Reader 进程的 CPU 占用却不低。
原因:大概率是分发命令积压。可能是订阅端有长时间阻塞锁,分发进程发了命令但订阅端提交不了;也可能是快照还在应用早期,增量命令一直在排队。
解决:先看分发积压。用 Windows 性能监视器加“SQL Server: Replication Distribution”计数器,看 Dist: Delivered Commands/sec 和 Undelivered Commands 两个值。Undelivered 一直涨而 Delivered 为 0,问题在订阅端:去订阅服务器执行 sp_who2 看阻塞链头,通常能找到持有锁的会话。如果两边都正常但没有吞吐,就在分发服务器上查 sysprocesses 找到对应的复制进程,KILL 掉让它自动重启。需要强调的是,KILL 前必须确认 program_name 里带 Replication 字样,否则误杀掉业务连接就是新的事故。这条经验基本算复制运维里最常用的“后悔药”,但别把它当成日常手段,频繁 KILL 说明根因还没找到。
6. 收尾前最后一道工序:行数与主键差集校验,顺带说 DataX 的边界
6.1 用行数与主键差集做一致性校验
同步链路调完,我每次都会随手跑一遍一致性验证。最原始但有效的是行数和累计值校验:
SELECT 'source' AS side, COUNT_BIG(*) AS rows_cnt, SUM(CAST(order_id AS bigint)) AS chk_sum FROM erp.dbo.orders UNION ALL SELECT 'target', COUNT_BIG(*), SUM(CAST(order_id AS bigint)) FROM erp_report.dbo.orders逻辑说明:两个 side 分别统计源库和目标库的行数、ID 累加值。参数说明:SUM(CAST(order_id AS bigint)) 是把 ID 转成 bigint 后累加,能挡掉 99% 的漏行和重行问题。这个校验不是密码学级的,但它能快速暴露行数不一致、主键漂移、重复数据这三大类故障。字段级比对我会抽几个数值型字段再各做一组 SUM,敏感字段则抽比例比对,不做全量网络传输,因为 2000 老机器的网络带宽经不起全量字段逐行比对。
6.2 增量同步的兜底习惯:夜间定时校验差异表
如果两套库主键差集有差异,用第 4.4 节那段 LEFT JOIN 脚本把差异主键写进一张专用的 diff 表。我的习惯是给每个事务复制发布对加一个夜间作业,运行这段差集逻辑,第二天早上只需要查 diff 表有没有新记录,就能判断一夜之间同步链路是否健康。这个方法让我从“两台 2000 到底一样不一样”的黑匣子状态里解脱出来,也省去了每天手动跑校验的重复劳动。
最后提醒一句 DataX 的边界:如果这个 SQL Server 2000 库还要作为源端持续被新平台抽取,DataX 这类数据库同步工具确实能做多个实例的增量同步,但 2000 的驱动非常老,JDBC/ODBC 的版本匹配、日期时间类型、numeric 精度都需要单独做一轮测试。生产账务数据我更信任原生事务复制的保底能力,不拿数据库同步工具去赌增量准确性。希望这个老库同步方案的选型思路和排查经验帮到你。
本文还有配套的精品资源,点击获取