ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SQL Server 2000双库同步实战:复制配置与增量脚本方案

SQL Server 2000双库同步实战:复制配置与增量脚本方案 简介这是一份关于SQL Server 2000数据库同步的实用指南面向需要维护多个SQL Server 2000实例的数据库运维与开发人员。资源聚焦如何保持两个数据库结构与内容一致围绕复制技术展开涵盖发布服务器、订阅服务器、分发服务器的配置流程以及Windows用户权限、SQL代理服务、身份验证模式、服务器注册与别名等前置设置并给出建立发布和订阅的具体操作方法。文中还提示了事务发布需有主键、合并发布会添加rowguid列等关键细节有助于规避同步过程中的常见问题。该资源为PDF格式共1个文件压缩包大小114KB。目前已有855人学习下载适合在SQL Server 2000环境下配置复制同步时参考。1. 双库内容同步SQL Server 2000 留给我们的现实问题接手过老系统的工程师都知道SQL Server 2000 至今还在不少银行、制造和政务的服务器里跑着不是不想换是业务不敢停。当两台机器上各有一个内容几乎一样的库需要保持数据一致时很多人第一反应是“直接备份恢复”但生产库不能每天停报表库要跟到分钟级。这个标题要解决的就是这类场景两个 SQLServer 数据库之间的内容同步无论是生产到报表、主库到灾备还是新旧系统分库都需要一套能落地的同步方案。这篇笔记会从方案选型、复制组件配置、增量拉取脚本讲到常见翻车点和事后排查尽量把 2000 这个年代的限制说清楚让新手能照着配熟手能避开参数坑。2. 先选定同步方案快照、复制、触发器、程序拉取哪种合适SQL Server 2000 时代没有今天这种“数据同步软件”的概念数据库同步工具也远没有现在丰富常见做法无非四种DTS 定时快照、复制服务、触发器跨库写入、自写程序按时间戳拉取。选型直接决定后面的维护成本先讲清楚每种方案的核心逻辑和适用边界。2.1 快照同步DTS 包定时整表覆盖快照的意思就是把源表的内容整个复制到目标表不做增量判断。对于数据量小、实时性要求低的场景这最省心比如每天凌晨把产品表从生产库同步到报表库报表查询只需要昨天的数据这个方案就够了。在企业管理器里走到“工具-数据转换服务-导入数据”选好源库和目标库在“指定表复制或查询”这一步选“从源数据库复制表和视图”勾选目标表最后保存 DTS 包。保存成包的原因是要让 SQL 代理能定时调它否则只能手动操作做不到定时同步。这里有个容易踩的细节DTS 的“复制表”默认只做插入和更新不会删除目标表里多出来的行。如果源表删了一行目标表里这行依然残留数据内容两边会对不上。想彻底保持一致就要在 DTS 包前面加一个“执行 SQL 任务”步骤先对目标表执行 DELETE再执行导入或者直接用“替换模式”。快照同步最适合单表数据小于几十万行的场景整表 DELETE 再 INSERT 的耗时通常能控制在几秒到一两分钟。如果表有几百上千万行每晚全量覆盖会白白占用大量 I/O而且目标表在删除期间查询会失败这种情况就别用快照直接看事务复制。2.2 事务复制秒级增量但它对表结构要求高事务复制是 SQL Server 2000 内置的同步数据库内容的主力方案原理是发布服务器的“日志读取器”代理不断读取事务日志把被修改的数据解析成命令存到分发数据库再由分发代理把变更应用到订阅服务器。因为是基于日志捕获而不是轮询查询延迟能做到秒级也不需要应用层配合改时间戳。但它对表结构有硬性要求发布表必须有主键否则日志读取器无法定位变更行。2000 的事务复制对 text、ntext、image 字段也有局限这些大字段的 UPDATE 在复制时经常不完全支持会出现源库改了内容、目标库没变的怪象。解决办法是尽量避免把大字段放进发布集合实在要同步要么换触发器方案要么把这些字段拆到另一张只做快照的表。配置路径是“复制-配置发布、订阅服务器和分发”先配置分发再创建发布最后添加订阅。这套流程在企业管理器里点来点去很容易漏步骤第 3 章我会给一套完整的脚本来梳理顺序。2.3 触发器同步适合双向但跨服务器容易死锁事务复制天生是单向的发布到订阅订阅端改了数据不会回流。如果业务需要两个库双向更新就得用触发器。在源表的 INSERT 触发器里写一句 INSERT 到链接服务器的目标表UPDATE 和 DELETE 分别写对应的同步语句逻辑直观也便于加业务过滤条件。但跨服务器触发器的代价很高链接服务器上的操作会触发分布式事务 MSDTC两台机器的时间不同步、端口被防火墙拦、MSDTC 没有配置好都会导致整个触发器事务回滚甚至牵连源库的正常写入。生产环境里我见过最典型的翻车是源库一台服务器、目标库一台位于不同网段的机器夜间批量更新 5 万行每行触发一次远程 INSERT结果 MSDTC 频繁超时批处理跑了三个小时还中途失败。触发器方案更适合小数据量、双向更新次数少的场景。如果每次同步成千上万行别用行级触发器改成“触发器里只记录变更到一张本地待同步表后台作业统一拉取”的设计能大幅降低锁冲突。2.4 程序拉取用时间戳自己控制同步节奏程序拉取是我个人在实际维护老库时最常用的一招因为它不依赖复制服务也不容易被 MSDTC 绑架。思路很简单在源表加一个 LastModified 字段每次同步时取上次同步时间点拉取这个时间点之后修改的行写入目标表。剩下的 SQL 逻辑完全由自己掌控延迟取决于定时作业的频率5 分钟一次到一小时一次都能设。这个方案最关键的前置条件是源表所有增删改路径都必然更新 LastModified。靠应用层 SQL 手写很难保证一致常见做法是在源表上加 UPDATE、INSERT 触发器去强制填充这个字段这样哪怕开发人员直接写 SQL 改数据也不会漏掉时间戳。对于 DELETE 操作还要额外建一个删除日志表或做标记删除因为时间戳字段被删掉后就不存在了。工具层面如果目标实例是 2005 及以上可以考虑用 DataX 这类数据库同步工具做批量拉取按 where 条件拼增量 SQL性能好、可监控但驱动要从 SQL Server 2000 的连接方式去适配。本文后面以 SQL 脚本和 SQL 代理为主因为这是全版本兼容、最不依赖外部环境的路线。3. 用事务复制同步两个库发布、分发、订阅的配置顺序与脚本选事务复制后最忌讳上来就在企业管理器里乱点。先把三个角色理清发布服务器是源库所在实例分发服务器负责存储复制中间数据订阅服务器是目标库。这三个角色可以都在一台机器上也可以分开。下面这套脚本在 SQL Server 2000 的查询分析器里按顺序执行能看得见每一步在做什么。3.1 启用分发三行脚本把复制基础搭起来在源实例的主库执行以下脚本-- 在源实例上执行将本机指定为分发服务器 EXEC sp_adddistributor distributor N源机器名, password N分发密码 -- 创建分发数据库distpub 目录用于存放快照文件 EXEC sp_adddistributiondb database Ndistribution -- 注册发布服务器和快照工作目录 EXEC sp_adddistpublisher publisher N源机器名, distribution_db Ndistribution, working_directory ND:\repldata参数说明distributor 填的是源实例的机器名2000 对名称解析很敏感建议先用 ping 确认连接名能通不能用 IP 代替机器名。working_directory 必须是本地磁盘绝对路径而且这台机器要能允许订阅服务器通过网络读取该共享目录。脚本执行成功后在企业管理器的复制节点下能看到刚才的配置这一步谁也不许跳复制代理是独立服务不配分发服务器后续发布和订阅全部白搭。3.2 创建发布与发布项哪些表能发、参数怎么写分发配好后启用源库的复制属性并创建发布。这一步可以全脚本完成-- 启用数据库参与复制 EXEC sp_replicationdboption dbname NYourDB, optname Npublish, value Ntrue -- 创建事务发布 EXEC sp_addpublication publication NPub_YourDB, repl_freq Ncontinuous, status Nactive, allow_push Ntrue, allow_pull Ntrue, sync_method Nnative -- 把 Orders 表加入发布 EXEC sp_addarticle publication NPub_YourDB, article NOrders, source_table NOrders, type Nlogbased, sync_object NOrders说明一下关键参数repl_freq 设为 continuous 表示事务复制会实时读取日志如果设成 scheduled 就变成定时快照不是我们要的秒级增量。sync_method 用 native 是生成 SQL Server 原生格式的初始化快照传输高效但跨平台场景不要用这种格式可以换 database。allow_push 和 allow_pull 分别表示是否允许推送订阅和拉取订阅建议都开后面灵活。需要注意的一个边界源表如果已经有大量数据加入发布后复制代理会对该表做全表快照期间会加共享锁大表可能导致业务查询阻塞。常见的做法是选在低峰期加发布或者先用 status 的 replicating 状态初始化再切到 active。我在实际项目里还把发表过是 text 类型的表单独拎出来不让它进事务发布避开前面提到的大字段同步缺陷。3.3 添加订阅与初始化推送订阅和拉订阅怎么选订阅有三种方式本地订阅服务器在源端添加、远程订阅服务器向源端提交、或者拉订阅在目标端创建。这里给出在源端添加推送订阅的脚本-- 在发布服务器上执行添加订阅 EXEC sp_addsubscription publication NPub_YourDB, subscriber N目标机器名, destination_db NTargetDB, subscription_type Npush, sync_type Nautomaticsync_type 设为 automatic 表示订阅添加后自动用快照初始化目标表如果目标表已经有结构但没数据可以设成 none跳过初始化只同步后续增量。这招在首次对接时特别有用目标表数据不是空的已有初始化数据的话快照会跟现有数据产生主键冲突所以把 sync_type 设为 none再手动补一次基线数据更可控。推送订阅和拉订阅的选择原则是源库和目标库在同一个内网且源库压力不大用推送订阅管理集中在源端如果目标库分布在多个地方或者源库不想被订阅连接占用过多资源用拉订阅每个目标库在本地创建自己的作业去分发服务器取数据。2000 对网络要求高跨互联网别用复制延迟和断线重连都是折磨。3.4 复制监控用 sp_replmonitor 和 Replication Monitor 看延迟复制配置完不是万事大吉延迟和错误都在背后悄悄发生。SQL Server 2000 提供了一把小工具叫 Replication Monitor位置在企业管理器的复制监视器目录下能直接看到每个发布到订阅的延迟秒数、各代理状态和历史会话。但 Replication Monitor 依赖 SQL 代理和 MSDTC两个服务必须在运行状态否则界面一片黑。命令行层面也有一个重用的存储过程-- 查看复制代理会话的最近错误 EXEC sp_replshowcmds publication NPub_YourDB -- 查看当前未分发命令数量数量持续增长说明发布端堆积 DBCC DBREINDEX(msdb.dbo.MSreplication_subscriptions) SELECT * FROM distribution..MSrepl_commands WITH (NOLOCK) WHERE publisher_database_id 0实际维护中我更看重未分发命令数这个指标。它表示日志读取器读了但还没有分发到订阅端的命令条数正常应该是 0 或很小如果持续涨到几万、几十万说明订阅端应用速度追不上发布端的写入速度或者分发代理卡住。这个黑匣子一定要盯住很多同步中断事故其实前一天就已经有堆积隐患了。4. 用时间戳字段做增量同步SQL 脚本、Agent 调度与断点续传事务复制虽然好用但对 2000 的限制多、管理复杂很多遗留系统里的表甚至没主键复制根本发不起来。这时候另一条路就是自己写增量同步。下面这套思路在 2000 上完全跑得通也是当时手工同步的主流做法。4.1 给旧表加 LastModified 字段历史数据初始化技巧给已经跑了好几年的表加字段要谨慎先看业务代码有没有直接写列名的 INSERT如果有加字段后这些语句会报错。我一般先做兼容处理设置默认值并用触发器兜底。ALTER TABLE Orders ADD LastModified DATETIME NOT NULL DEFAULT GETDATE() -- 历史数据统一初始化避免全表都是 1900 年之前的默认值 UPDATE Orders SET LastModified GETDATE() WHERE LastModified IS NULL -- 为了不让任何应用绕过 LastModified增加插入和更新触发器强制覆盖 CREATE TRIGGER trg_Orders_MarkTime ON Orders AFTER INSERT, UPDATE AS BEGIN UPDATE o SET LastModified GETDATE() FROM Orders o JOIN inserted i ON o.OrderID i.OrderID END逻辑说明ALTER TABLE 加字段时如果不带 NOT NULL旧行该字段会是 NULL后面同步脚本用 is not null 判断增量时这些行会被漏掉所以必须做历史初始化。触发器的目的是让所有写入路径都自动刷新时间戳不再依赖应用层有没有更新这个字段。参数说明这里用了 AFTER 触发器而不是 INSTEAD OF因为 2000 对 INSTEAD 触发器的限制更多而且 AFTER 能在 UPDATE 完成后重新写时间戳减少对原语句的影响。这个设计对 DELETE 事件无能为力行被删了触发器也找不到目标。所以同步需求里如果有删除必须同步删除就得同时建一张 DeleteLog 表在 DELETE 触发器里记录被删行的主键和删除时间同步任务再拿这张表去目标库执行 DELETE。4.2 在 SQL Server 2000 里手动实现 UPSERT没有 MERGE 的等价值写法2000 没有 MERGE 语句多表更新也常踩语法坑。我的标准姿势是先把增量数据拉到一个临时表再对临时表逐条做存在性判断。下面这套写法兼容 2000也能平移到 2005 及以上环境-- 在目标库执行 DECLARE lastSync DATETIME SET lastSync 2024-06-01 00:00:00 -- 实际取自已保存的控制表见 4.4 -- 通过链接服务器把增量拉进临时表 SELECT OrderID, CustomerID, OrderDate, LastModified INTO #tmpSync FROM [源机器].YourDB.dbo.Orders WITH (NOLOCK) WHERE LastModified lastSync -- 对临时表做 UPSERT先更新更新不到再插入 UPDATE t SET t.CustomerID s.CustomerID, t.OrderDate s.OrderDate, t.LastModified s.LastModified FROM YourDB.dbo.Orders t JOIN #tmpSync s ON t.OrderID s.OrderID INSERT INTO YourDB.dbo.Orders (OrderID, CustomerID, OrderDate, LastModified) SELECT s.OrderID, s.CustomerID, s.OrderDate, s.LastModified FROM #tmpSync s WHERE NOT EXISTS (SELECT 1 FROM YourDB.dbo.Orders t WHERE t.OrderID s.OrderID) DROP TABLE #tmpSync逻辑说明先更新后插入的顺序很关键如果目标表里没有这条记录UPDATE 影响行数为 0随后 INSERT 补上。两段式语句避免了游标逐行操作性能远高于循环。参数说明WITH (NOLOCK) 是一个脏读提示因为同步任务不想阻塞源库的在线业务也能避免源库正在大事务时这边读到的是锁等待状态代价是可能读到未提交数据判断是否能接受一般用在订单表问题不大用在资金账务表就要去掉 NOLOCK。同步时间字段本身也要同步否则目标库的 LastModified 始终是首次插入的时间下一次同步会因为时间戳比 lastSync 早而漏掉它的后续修改。这里血泪教训很多很多新手同步完忘记更新目标表的 LastModified结果同一条记录永远只同步一次。4.3 SQL Agent 作业每 5 分钟跑一次同步的调度配置增量脚本写好只是第一步怎么调度、失败怎么重试才是生产级考量。用 SQL 代理创建作业在企业管理器里填比较好点但有 SQL 基础的人直接写脚本更快-- 在目标实例上创建 SQL 代理作业 EXEC msdb.dbo.sp_add_job job_name NSync_Orders_From_Prod EXEC msdb.dbo.sp_add_jobstep job_name NSync_Orders_From_Prod, step_name NUPSERT Orders, subsystem NTSQL, command N上面那套 UPSERT 脚本, database_name NTargetDB EXEC msdb.dbo.sp_add_schedule schedule_name NEvery5Min, freq_type 4, freq_interval 1, freq_subday_type 4, freq_subday_interval 5, active_start_time 000000 EXEC msdb.dbo.sp_attach_schedule job_name NSync_Orders_From_Prod, schedule_name NEvery5Min EXEC msdb.dbo.sp_start_job job_name NSync_Orders_From_Prod参数说明freq_type4 表示每天循环的调度freq_subday_type4 表示按分钟间隔freq_subday_interval5 就是每 5 分钟一次。如果希望业务低谷之外再限制窗口加 active_start_time 和 active_end_time 就能控制只在白天或晚上某段时间同步。注意 2000 的 SQL 代理作业失败后默认只标记失败不自动重试我一般把调度时间加密到 1 分钟同一份同步作业在 5 分钟内重复执行也不会产生重复数据因为 UPSERT 的幂等性保证了重复跑结果一致。4.4 断点续传同步控制表防止重复与漏数据把 lastSync 写死在脚本里太脆弱生产环境必须用控制表保存上次同步进度。我在目标库建一张单行控制表每次同步前读取、同步后更新做到断电重跑也不重不漏-- 控制表 CREATE TABLE SyncControl ( SyncKey VARCHAR(50) NOT NULL, LastSyncTime DATETIME NULL, SyncCount INT DEFAULT 0, LastRunResult VARCHAR(200) , LastRunAt DATETIME NULL ) INSERT INTO SyncControl VALUES (OrderSync, 2024-06-01, 0, , GETDATE()) -- 同步脚本开头取上次时间 DECLARE lastSync DATETIME SELECT lastSync LastSyncTime FROM SyncControl WHERE SyncKey OrderSync -- ... 同步主体 ... -- 同步结束后更新控制表 UPDATE SyncControl SET LastSyncTime GETDATE(), SyncCount (SELECT COUNT(*) FROM #tmpSync), LastRunResult SUCCESS, LastRunAt GETDATE() WHERE SyncKey OrderSync这个表的额外价值SyncCount 记录每次同步行数LastRunResult 记录结果第二天上班扫一眼这张表就知道昨晚哪一次同步异常。实际维护里我不仅在控制表里记录最后时间还留了一个 LastRunAt用来和源库当前最大 LastModified 做比较一旦发现目标表最新数据比源库源表落后超过一个调度周期就说明链路有问题报警比凭感觉查日志快得多。5. SQL Server 2000 同步常见问题排查四个真实翻车场景方案选得再好配置再细生产环境还是会给你上课。这一章把我在 2000 上遇到的四类同步故障整理成固定套路按“现象 → 原因 → 解决”的顺序写方便直接对号入座。5.1 复制代理一直等待快照本地目录权限和共享名对不上现象添加订阅后订阅端显示“等待快照应用”1 小时过去状态没变数据库中一张表数据是空的Replication Monitor 里的快照代理一直处于未启动或失败状态。原因分发服务器上的快照工作目录 D:\repldata 没有被共享或者共享了但订阅服务器使用的 SQL 代理账户无权限访问。2000 的订阅初始化是通过网络共享读取快照的目录必须共享为类似 REPLDATA 的名字。另一个隐藏原因SQL 代理服务账户如果是本地系统账户则对其他机器共享的访问依赖机器账户的凭据常常在域环境下能通在纯工作组环境就失败。解决把 D:\repldata 右键共享共享名设为 REPLDATA权限里加入“Everyone”读权限或明确加入订阅服务器机器账户。然后重启分发服务器上的 SQL 代理服务订阅端右键该订阅选“重新初始化”并勾选“使用新快照”重新生成立即可。如果还是失败在订阅服务器上用同一账户手动访问 \源机器\REPLDATA 看能不能列出文件能列出来就说明共享正常问题在复制代理的服务账户。5.2 链接服务器同步死锁MSDTC 嵌套事务拖垮了整个更新现象采用触发器方案时源库一条 UPDATE 语句更新了几千行目标库同步了一半然后整个事务回滚源库该表的所有更新全部被阻塞重启 SQL 服务后才恢复。原因每个触发器里的链接服务器写入参与了分布式事务MSDTC 协调连接两台服务器只要任一方网络闪断或事务超时整个本地事务也会跟着回滚。大量行更新时并发触发器会引发锁升级和分布式锁的复杂交互导致第 N 行出现死锁整个事务被系统选为死锁牺牲品。解决先给源库分布式事务配置足够长的超时在源库执行SET XACT_ABORT ON让事务行为可预期。第二条路是去掉触发器行级同步改成触发器把主键写入待同步表后台作业每 10 秒读待同步表再批量拉数据把分布式事务从业务路径里移走。实际上这个改动把问题彻底转移到了程序拉取模式死锁问题就没了。如果临时只能保留触发器那就要限制每次更新的数据量比如应用层分批提交一次别超过 500 行。5.3 时间戳字段被更新掉应用层写死了字段导致增量失效现象目标库数据比源库少追踪发现某张表的 LastModified 字段很多行是最初初始化时的默认值明明源库更新过但目标库没同步过去。原因应用层有一条 UPDATE 语句显式把 LastModified 设成了某个固定值比如UPDATE Orders SET Status完成, LastModified2024-01-01 WHERE ...这种写法直接覆盖了触发器设置的时间。触发器的 UPDATE 触发器重新设了 GETDATE()但源库这条语句里写死了旧时间触发器里的 UPDATE 语句又把时间改成当前时间才对——但这里的一个坑是如果触发器执行顺序有问题或者应用层在触发器之前就把事务回滚了最后留下的时间戳仍然是过去的。实际生产里更多是因为应用层没有做任何改动而开发人员手动用企业管理器修改了数据企业管理器的表编辑工具不触发 AFTER UPDATE 触发器时间戳保持旧值。解决如果没有办法约束应用层只能把触发器的判断逻辑改成“只要主键出现在 inserted 里就无条件置为当前时间”防止任何显式赋值覆盖。另外 2000 的表编辑器和 SELECT INTO 操作不触发触发器这类数据变更只能靠同步任务做全量比对兜底。最稳妥的兜底是在同步脚本里增加一个偏离检查SELECT COUNT(*) FROM 源表 s WHERE NOT EXISTS (SELECT 1 FROM 目标表 t WHERE s.OrderIDt.OrderID AND s.LastModifiedt.LastModified)返回不等于 0 就发警告这样就算时间戳被折腾出问题至少能发现。5.4 2000 实例和 2005 实例混搭兼容级别与 ODBC 驱动的兼容坑现象从 SQL Server 2005 实例创建链接服务器指向 2000 实例同步大表时报“不支持的数据类型”或 OLE DB 错误部分数据同步过去目标库编码乱。原因2005 之后新增的数据类型比如 varchar(max)、datetime2在 2000 的 OLE DB 提供程序里没有对应映射链接服务器查询时会把类型降级或失败。反过来2000 作为链接服务器源时ODBC 驱动必须用旧版 SQL Server Native Client 8.0 或 MDAC新版驱动在高版本系统上默认不兼容 2000。解决2000 实例保持兼容级别 80可以用exec sp_dbcmptlevel YourDB, 80设置别让数据库跑到 90 或更高级别链接服务器创建时 Provider 选择 Microsoft OLE DB Provider for SQL ServerSQLOLEDB禁用 TCP/IP 动态端口用固定端口 1433同时在“服务器选项”中取消勾选“允许进程内”避免 OLE DB 进程内调用导致的锁问题。如果混合实例之间有大量大字段同步最稳的还是回到普通快照加作业的方案把 2000 的数据导出为临时表后再特殊处理。6. 让同步真正可信日志表、比对脚本与一次事故教训同步跑通了只是起点真正让人放心的是同步结果可验证、过程可追溯。这一章说说我后来怎么做同步验证和异常恢复。6.1 每跑一次同步都写日志表从结果反推失败原因我在目标库建一张统一的 SyncRunLog 表每次作业跑完必写一条记录包括同步任务名、开始时间、结束时间、影响行数、执行结果。排查问题时不必去翻 SQL 代理的历史记录直接在这张表里按时间查更直观CREATE TABLE SyncRunLog ( LogID INT IDENTITY PRIMARY KEY, SyncTask VARCHAR(50), StartAt DATETIME, EndAt DATETIME, AffectedRows INT, Result VARCHAR(200), ErrMsg VARCHAR(2000) )这张表是同步任务的黑匣子也是出问题时的后悔药。有一次我在生产环境里凌晨 2 点的同步一直失败第二天早上才发现目标库和源库差了一整点数据幸好有日志表可以看到失败发生在哪一步、操作了哪些数据后台补数据就知道了边界。6.2 没有时间戳的表做整表差异比对用 CHECKSUM 和 COUNT 找出不一致行有些老表没法加 LastModified 字段那就用差集比对。2000 没有 HASHBYTES我一般用 CHECKSUM 做每行签名再比对整表数据SELECT COUNT(*) 相同行数 FROM ( SELECT CHECKSUM(OrderID, CustomerID, OrderDate) AS Ck FROM 源库.Orders INTERSECT SELECT CHECKSUM(T.OrderID, T.CustomerID, T.OrderDate) FROM 目标库.Orders T ) X SELECT DISTINCT 不一致行的主键 FROM ( SELECT CHECKSUM(OrderID, CustomerID, OrderDate) AS Ck FROM 源库.Orders UNION ALL SELECT CHECKSUM(OrderID, CustomerID, OrderDate) FROM 目标库.Orders ) X GROUP BY Ck HAVING COUNT(*) 2这里的逻辑是取两边的 CHECKSUM 做交叠统计如果每行的签名在两边都出现一次说明数据一致如果某签名只出现一次那就是这一行两边不一致。2000 支持 UNION ALL 和 GROUP BY这套语句可以直接跑。比对频率不用太高每天一次就够目的是兜住时间戳同步漏掉的那部分删除和更新。6.3 凌晨 2 点同步失败后的排查顺序先看日志、再查代理、最后补数据如果某天早上进公司发现日志表里 02:00 的同步任务 Result 列写着 FAILED不要慌按这个顺序排查先看 SyncRunLog 的 ErrMsg 有没有明确报错比如超时、死锁、找不到表没有再去 SQL 代理的历史记录里看作业步骤失败原因再看源库当时的锁状态和事务日志空间。排出来之后再决定是重新跑本次同步还是接受延迟并入下一次。这种从日志出发的顺序能避免很多“点来点去查一上午”的情况。同步两个 SQLServer 数据库的内容在没有现代化数据同步工具的时代靠的是精细的配置和严格的日志习惯。我一直记着那次凌晨失败没人管、到早会数据落后一截的教训后来每搭一套同步必先建日志表、再做一次全量比对、最后才设作业调度。希望帮到你。本文还有配套的精品资源点击获取
返回列表