在SQL Server中同步两个数据库


16

我有两个SQL Server数据库。一个是客户端(Windows应用程序),第二个是服务器上。我想每隔一段时间(例如每2分钟!)同步这两个数据库。

我已经阅读了有关同步的不同方法,例如复制,时间戳,使用触发器的日志表,Microsoft Sync Framework等。

实际上,我不喜欢使用可能是黑匣子的同步方法(例如复制),因为我不希望在更新SQL Server特定表并将其与服务器同步时阻止SQL Server特定表。

  1. 在这种情况下,您认为我应该使用哪种方法?请记住,每隔几分钟,我必须将几个表更改从客户端发送到服务器,并且还要从服务器获取两个表更改。

  2. 我发现了一种奇怪但又新的方法。是否可以在客户端中记录所有已执行(针对特定首选)的存储过程,并将其参数与.sql文件一起发送到服务器,然后在服务器上执行?在服务器上也会发生同样的情况,并将其发送给客户端。您是否认为这是一种简单但有用的方法?

  3. 如果可以的话,请建议我任何有用的方法。非常感谢。

编辑:请记住,这是实时同步,这使其与众不同。这意味着当客户端用户使用表时,与服务器的同步过程必须每隔几分钟进行一次,因此任何表都不得锁定。


1
请记住,这些“黑匣子”在其工作方式,如何维护和监视它们以及在常见(但不太常见)的故障情况下可以采取的措施方面都记录得比较好。我将考虑采用自己的同步方法,并且必须并且仅当我有非常特定于应用程序的需求(部分同步或需要用户同步)时,才发现并修复与“黑匣子”很久以前解决的边缘情况相关的错误。交互式冲突解决,等等)。
David Spillett

@DavidSpillett:您是否已在实时同步项目中成功使用复制?我主要关心的是实时同步和“锁定与阻止”。
Emad Farrokhi 2015年

Answers:


14

好吧,我可能听不到,但是我尝试回答。

您说您需要一个经常运行(至少两分钟)的高性能解决方案,并且需要一种可以快速锁定的良好方法。但是您不需要黑盒系统。

您会尝试再次发明轮子并构建自己的解决方案,而不是在数百万次安装中使用的黑匣子系统,都取得了不错的效果?嗯,听起来有点怪。

实际上,这些是我的建议。

  1. 即使您说过将不会使用复制。这是您可以使用的最简单和最佳的解决方案。复制易于设置,快速复制,您无需再次发明轮子。如果您只是对锁定感到奇怪,可以尝试将设置ISOLATION LEVELREAD_COMMITTED_SNAPSHOT。您可以在此处了解更多信息。这将用完tempdb的一部分,但是表始终是可读写的,并且复制可以在后台进行。

请参见下面的示例:

ALTER DATABASE yourDatabase SET ALLOW_SNAPSHOT_ISOLATION ON
ALTER DATABASE yourDatabase SET READ_COMMITTED_SNAPSHOT ON
  1. CDC(更改数据捕获)也可以是一种解决方案。但是通过这种方式,您需要自己构建几乎所有内容。CDC在某些情况下,我的经验可能是一件脆弱的事情。CDC将捕获监视表中的所有数据(您需要手动指定每个监视表)。之后,您会后得到前值和值INSERTUPDATEDELETECDC会将这些信息保留一段时间(您可以自行指定)。该方法可能用于CDC需要监视的某些表,并将这些更改手动复制到其他数据库。顺便说一下,也CDC可以在后台使用SQL Server复制。;-)您可以在此处了解更多信息。

警告:CDC不会知道DDL-changes。这意味着,如果您更改表并添加新列,CDC它将监视该表,但忽略对新列的所有更改。实际上,它仅记录NULL为前值和后值。- DDL更改为监视表后,需要重新初始化它。

  1. 上面描述的方式类似于使用SQL Server Profiler捕获工作负载,然后针对某些基准在另一个数据库上再次运行它。好吧,它可以工作。但是,副作用太多的事实对我来说太重了。如果在客户机上捕获了过程调用,该怎么办。之后在主数据库上运行相同命令,因为它不同步?该过程可能会贯穿整个过程,但可能会删除/更新/插入客户端中不存在的行。或者,您如何用一种原则处理多个客户。我认为这太棘手了。在最坏的情况下,您可能会破坏自己的诚信。
  2. 另一个想法可能是基于应用程序或使用触发器。取决于要同步的表数量。您可以将所有更改写到单独的临时表中,然后运行SQL Server代理作业所有x分钟,以将临时表中的这些行与主数据库同步。但是,如果您尝试同步(例如)150个表,则可能会有些沉重。您会有很大的开销。

好吧,这是我的2美分。希望您有一个很好的概述,也许您找到了一个适合您的解决方案。


9

在我理解它们的过程中,我将尝试列举一些优点和缺点的选项:

  1. SQL Server复制 -这是用于此任务的最佳,最优化的本机SQL Server工具。但有几个问题: 一。对于所有客户端,无论是否为SQL Express数据库,您都需要SQL Server CAL许可证。使用每个处理器许可可以避免这种情况。b。您不能按照此处同步SQL CE客户端。C。SQL Express或LocalDB不能充当发​​布者或分发者,因此您对客户端的复制过程控制较少。
  2. Microsoft Sync Framework-对我来说似乎更适合较小的移动应用程序数据库。它向数据库中添加了很多表,并且效率不如复制。由于它是在SQL Server外部作为组件实现的,因此配置起来会更加困难。我没有经验,只是尝试过并决定不使用它。

  3. 数据库更改跟踪。它是SQL Server的内置功能,可为您更改跟踪,包括插入,更新和删除。其他所有事情,例如发送和应用更改,解决冲突等,您都必须自己编写代码。

  4. Rowversion(时间戳)列如果您禁止所有删除操作(不同步删除的记录),则可以仅基于Rowversion信息实施自己的解决方案。SQL Server复制也使用Rowversion列,因此无论如何您都需要添加它们。
  5. Ionic的答案中提到的CDC-我没有经验,因为它仅在Enterprise或Developer版本中可用。

  6. 使用自己的技巧记录执行的存储过程-在很大程度上取决于数据库应用程序的性质。但是,当程序之间的差异不大时,您可能会在数据中造成很大的混乱。您将如何处理冲突?

从您的问题看来,您只需要同步少数几个表,而不是整个大型数据库。为此,您应该比问题中指定的内容更详细地分析需求,例如:

  • 可以发生删除,然后发生什么吗?
  • 冲突会发生吗?如何预防冲突以及如何解决冲突?
  • 我将如何处理表结构更改?
  • ...

如果您最终发现,删除和冲突不是您的问题,并且您的结构不会有太大变化,则可以考虑编写自己的逻辑,但是它可以轻松地增长到1000行代码。


2

谢谢大家的反馈。

我通过捕获执行的存储过程而不是一堆,而是一个接一个地捕获了成功的存储过程,从而成功地解决了同步过程,这对我来说很有效。由于已经认真考虑了完整性和所有方面,因此该系统一直在实时运行。


太好了,但是您可以详细说明您做了什么。您是否简单地记录已执行的存储过程的调用并将它们存储在某个临时表/脚本中,并让作业运行此脚本并设置一个字段(例如,您对所有这些说的,例如bit字段或datetime字段)尚未处理的记录会对其进行处理并更新位字段?)我很高兴您解决了您的问题,但是您需要对帮助他人学习所做的事情提供更多的见解?
JonH

0

答案较晚,但可能有助于吸引访问者

我试图在不同服务器之间分配数据并使用第三方工具(用于模式更改的Diff和用于数据更改同步的DataDiff)并遵循使该过程自动化所需的PowerShell脚本解决了类似的难题:

#check for the existence of the Outputs folder
function CheckAndCreateFolder($rootFolder, [switch]$Outputs)
{
$location = $rootFolder

#setting up location 
if($Outputs -eq $true)
{
    $location += "\Outputs"
}

#if the folder doesn't exist it will be created
if(-not (Test-Path $location))
{ mkdir $location -Force:$true -Confirm:$false | Out-Null }

return $location
}

#root folder for the schema sync process
$rootFolder = "SchemaSync"

#schema output summaries location 
$outsLoc = CheckAndCreateFolder $rootFolder -Outputs

#ApexSQL Diff location, date stamp variable is defined, along with tools parameters 
$diffLoc   = "ApexSQLDiff"
$stamp = (Get-Date -Format "MMddyyyy_HHMMss") 
$Params = "/pr:""MyProject.axds""    /out:""$outsLoc\SchemaOutput_$stamp.txt"" /sync /v /f" 
$returnCode = $LASTEXITCODE

#initiate the schema comparison and synchronization process
(Invoke-Expression ("& `"" + $diffLoc +"`" " +$Params))

#write output to file
"$outsLoc\SchemaOutput_$dateStamp.txt"

#schema changes are detected
if($returnCode -eq 0)
{
"`r`n $returnCode - Schema changes were successfully synchronized" >> 

}
else
{
#there are no schema changes
if($returnCode -eq 102)
{
"`r`n $returnCode - There are no schema changes. Job aborted" >> 
}
#an error is encountered
else
{
"`r`n $returnCode - An error is encountered" >> 

#output file is opened when an error is encountered
Invoke-Item "$outsLoc\SchemaOutput_$stamp.txt"
}

}

此方法可安排两个数据库之间的比较,并实时同步发现的更改。以下是一些提供逐步说明的文章:

https://solutioncenter.apexsql.com/automatically-compare-and-synchronize-sql-server-data/ https://solutioncenter.apexsql.com/how-to-automatically-keep-two-sql-server-database-同步模式/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.