本主题介绍如何使用 SQL Server Management Studio、Transact-SQL 或复制管理对象(RMO)在 SQL Server 2014 中的订阅服务器中验证数据。
通过事务复制和合并复制,可以验证订阅服务器上的数据是否与发布服务器上的数据匹配。 可以对特定订阅或对某个出版物的所有订阅进行验证。 指定以下验证类型之一,分发代理或合并代理将在下次运行时验证数据:
- 只计行数 这会验证订阅服务器上的表是否与发布服务器上的表具有相同的行数,但不验证行的内容是否匹配。 行计数验证提供了一种轻型验证方法,可让你了解数据问题。
- 行计数和二进制校验和。 除了在发布服务器和订阅服务器上获取行计数外,还会使用校验和算法计算所有数据的校验和。 如果行计数失败,则不会执行校验和。
除了验证订阅服务器和发布服务器上的数据是否一致外,合并复制还提供了验证数据是否为每个订阅服务器正确分区的能力。 有关详细信息,请参阅 验证合并订阅者的分区信息。
数据验证的工作原理
SQL Server 通过计算发布服务器上的行计数或校验和来验证数据,然后将这些值与订阅服务器上计算的行计数或校验和进行比较。 为整个发布表计算一个值,为整个订阅表计算一个值,但计算时不包括text
、ntext
或image
列中的数据。
执行计算时,共享锁临时放置在运行行计数或校验和的表上,但计算很快完成,共享锁通常会在几秒钟内删除。
使用二进制校验和时,32位冗余检查(CRC)是逐列进行的,而不是在数据页上的物理行上进行CRC。 这样,表格中的列可以按照数据页上的任何物理顺序排列,但仍然会计算出同一行的 CRC。 当发布上有行或列筛选器时,可以使用二进制校验和验证。
验证数据由三部分组成:
将单个订阅或某出版物的所有订阅标记为验证。 将订阅标记以便在 验证订阅、验证订阅和验证所有订阅对话框中进行验证,这些对话框位于 Microsoft SQL Server Management Studio 中的 本地发布 文件夹和本地订阅 文件夹。 还可以从“ 所有订阅 ”选项卡、 “订阅监视列表 ”选项卡和复制监视器中的发布节点标记订阅。 有关启动复制监视器的信息,请参阅 “启动复制监视器”。
当订阅下次由分发代理(用于事务复制)或合并代理(用于合并复制)同步时,它会被验证。 分发代理通常持续运行,在这种情况下,将立即进行验证;合并代理通常按需运行,在这种情况下,在运行代理后进行验证。
查看验证结果:
- 在复制监视器的详细信息窗口中:分发服务器到订阅服务器历史记录选项卡用于事务复制,同步历史记录选项卡用于合并复制。
- 在 Management Studio 的 “查看同步状态 ”对话框中。
注意事项和限制
- 复制监视器的过程仅适用于推送订阅,因为无法在复制监视器中同步拉取订阅。 但是,可以标记订阅进行验证,并在复制监视器中查看拉取订阅的验证结果。
- 验证结果指示验证是成功还是失败,但不指定发生失败时哪些行未通过验证。 若要比较发布者和订阅者上的数据,请使用 tablediff 工具。 有关将此实用工具用于复制数据的详细信息,请参阅比较复制表的差异(复制编程)。
验证数据时,请考虑以下问题:
在验证数据之前,必须在订阅服务器上停止所有更新活动(在发生验证时不必在发布服务器上停止活动)。
由于校验和和二进制校验和在验证大型数据集时可能需要大量的处理器资源,因此应在复制所用服务器活动最少时安排验证。
复制仅验证表;它不验证仅架构的项目(如存储过程)在发布者和订阅者之间是否相同。
二进制校验码可以用于任何已发布的表。 校验和不能验证具有列过滤器的表,或由于ALTER TABLE语句删除或添加列而导致列偏移量不同的逻辑表结构。
复制验证使用
checksum
和 binary_checksum 函数。 有关其行为的信息,请参阅 CHECKSUM(Transact-SQL)和BINARY_CHECKSUM(Transact-SQL)。如果使用二进制校验和或校验和进行验证,如果数据类型在订阅服务器上与发布服务器不同,则错误地报告失败。 如果执行下列作之一,可能会发生这种情况:
- 显式设置架构选项以映射早期版本的 SQL Server 的数据类型。
- 将合并发布的发布兼容性级别设置为 SQL Server 的早期版本,而已发布的表包含必须为此版本映射的一个或多个数据类型。
- 手动初始化订阅,并在订阅者端使用不同的数据类型。
事务复制的可转换订阅不支持二进制校验和及其验证。
复制到非 SQL Server 订阅服务器的数据不支持验证。
数据验证结果
验证完成后,分发代理或合并代理会记录有关成功或失败的消息(复制不会报告哪些行失败)。 可以在 SQL Server Management Studio、复制监视器和复制系统表中查看这些消息。 上述操作说明主题演示了如何进行验证并查看结果。
若要处理验证失败,请考虑以下事项:
配置名为 复制的复制警报:订阅服务器的数据验证失败 ,以便收到失败的通知。 有关详细信息,请参阅[配置预定义复制警报(SQL Server Management Studio)(administration/configure-predefined-replication-alerts-sql-server-management-studio.md)。
验证失败是否对您的应用程序造成了问题? 如果验证失败是问题,请手动更新数据,使其同步或重新初始化订阅:
可以使用 表差异工具更新数据。 有关使用此实用工具的详细信息,请参阅“比较复制表的差异”(复制编程)。
有关 reinitializaton 的详细信息,请参阅 重新初始化订阅。
事务性复制中的文章
使用 SQL Server Management Studio
在 SQL Server Management Studio 中连接到发布者,然后展开该服务器节点。
展开 “复制 ”文件夹,然后展开 “本地发布” 文件夹。
右键单击要为其验证订阅的发布的项目,然后单击“验证订阅”。
在“ 验证订阅 ”对话框中,选择要验证的订阅:
- 选择“ 验证所有 SQL Server 订阅”。
- 选择“ 验证以下订阅”,然后选择一个或多个订阅。
若要指定要执行的验证类型(行计数或行计数和校验和),请单击 “验证选项”,然后在“ 订阅验证选项 ”对话框中指定选项。
单击 “确定” 。
在复制监视器或 “查看同步状态 ”对话框中查看验证结果。 对于每个订阅:
- 展开发布,右键单击订阅,然后单击“ 查看同步状态”。
- 如果代理未运行,请单击“查看同步状态”对话框中的“开始”。 该对话框将显示有关验证的信息性消息。
如果看不到有关验证的任何消息,代理已记录后续消息。 在这种情况下,在复制监视器中查看验证结果。 有关详细信息,请参阅本主题中有关复制监视器的操作指南。
使用 Transact-SQL (T-SQL)
所有文章
在发行商的出版物数据库中,执行sp_publication_validation(Transact-SQL)。 为@rowcount_only指定@publication和以下值之一:
- 1 - 仅行数检查(默认值)
- 2 - 行计数和二进制校验和。
注释
执行sp_publication_validation(Transact-SQL)时,将为发布中的每个项目执行sp_article_validation(Transact-SQL)。 若要成功执行 sp_publication_validation(Transact-SQL),您必须对已发布基表中的所有列具有 SELECT 权限。
检查代理输出中是否存在验证结果。 有关详细信息,请参阅 “验证复制的数据”。
单一篇文章
在发布服务器上,对发布数据库执行sp_article_validation(Transact-SQL)。 指定 @publication、 @article项目的名称,并为 @rowcount_only指定以下值之一:
- 1 - 仅行计数检查(默认值)
- 2 - 行计数和二进制校验和。
注释
若要成功执行 sp_article_validation(Transact-SQL),您必须对已发布基表中的所有列具有 SELECT 权限。
检查代理输出中是否存在验证结果。 有关详细信息,请参阅 “验证复制的数据”。
单个订阅者
在发布数据库上,使用BEGIN TRANSACTION(Transact-SQL)打开显式事务。
在发布服务器上,对发布数据库执行sp_marksubscriptionvalidation(Transact-SQL)验证。 指定 @publication 发布的项目、@subscriber 的订阅者名称以及 @destination_db 的订阅数据库名称。
(可选)对要验证的每个订阅重复步骤 2。
在发布服务器上,对发布数据库执行sp_article_validation(Transact-SQL)。 指定 @publication、 @article项目的名称,并为 @rowcount_only指定以下值之一:
- 1 - 仅行计数检查(默认值)
- 2 - 行计数和二进制校验值。
注释
若要成功执行 sp_article_validation(Transact-SQL),您必须对已发布基表中的所有列具有 SELECT 权限。
在发布者的发布数据库中,使用 COMMIT TRANSACTION(Transact-SQL)提交事务。
(可选)对正在验证的每个项目重复步骤 1 到 5。
检查代理输出中是否存在验证结果。 有关详细信息,请参阅 订阅服务器上的“验证数据”。
事务性发布的所有推送订阅
使用复制监视器
- 在复制监视器中,展开左窗格中的发布服务器组,然后展开发布服务器。
- 右键单击要为其验证订阅的发布项,然后单击验证订阅。
- 在“ 验证订阅 ”对话框中,选择要验证的订阅:
- 选择“ 验证所有 SQL Server 订阅”。
- 选择“ 验证以下订阅”,然后选择一个或多个订阅。
- 若要指定要执行的验证类型(行计数或行计数和校验和),请单击 “验证选项”,然后在“ 订阅验证选项 ”对话框中指定选项。
- 单击 “确定” 。
- 单击“ 所有订阅 ”选项卡。
- 查看验证结果。 对于每个推送订阅:
- 如果代理未运行,请右键单击订阅,然后单击“ 开始同步”。
- 右键单击订阅,然后单击“ 查看详细信息”。
- 在所选会话文本区域中的“作”中查看“分发服务器到订阅服务器历史记录”选项卡的信息。
对于合并出版物的单个订阅
使用 SQL Server Management Studio
在 SQL Server Management Studio 中连接到发布者,然后展开该服务器节点。
展开 “复制 ”文件夹,然后展开 “本地发布” 文件夹。
展开包含要验证订阅的发布,右键单击该订阅,然后单击“验证订阅”。
在“ 验证订阅 ”对话框中,选择“ 验证此订阅”。
若要指定要执行的验证类型(行计数或行计数和校验和),请单击 “选项”,然后在“ 订阅验证选项 ”对话框中指定选项。
单击 “确定” 。
在“复制监视器”或“ 查看同步状态 ”对话框中查看验证结果:
- 展开发布,右键单击订阅,然后单击“ 查看同步状态”。
- 如果代理未运行,请单击“查看同步状态”对话框中的“开始”。 该对话框将显示有关验证的信息性消息。
如果看不到有关验证的任何消息,代理已记录后续消息。 在这种情况下,在复制监视器中查看验证结果。 有关详细信息,请参阅本主题中有关如何使用复制监视器的操作步骤。
使用 Transact-SQL (T-SQL)
在发布者的发布数据库上,执行 sp_validatemergesubscription (Transact-SQL)。 指定 @publication、 @subscriber订阅服务器的名称、 @subscriber_db的订阅数据库的名称,以及 @level的以下值之一:
- 1 - 仅行计数验证。
- 3 - 行计数二进制校验和验证。
这标记所选的订阅以进行验证。
检查代理输出中是否存在验证结果。
对要验证的每个订阅重复步骤 1 到 3。
注释
还可以通过在运行复制合并代理时指定 -Validate 参数,在同步结束时验证合并发布的订阅。
对于合并发布(Merge Publication)的所有订阅
使用 SQL Server Management Studio
在 SQL Server Management Studio 中连接到发布者,然后展开该服务器节点。
展开 “复制 ”文件夹,然后展开 “本地发布” 文件夹。
右键单击要为其验证订阅的发布,然后单击“ 验证所有订阅”。
在“ 验证所有订阅 ”对话框中,指定要执行的验证类型(行计数或行计数和校验和)。
单击 “确定” 。
在复制监视器或 “查看同步状态 ”对话框中查看验证结果。 对于每个订阅:
- 展开发布,右键单击订阅,然后单击“ 查看同步状态”。
- 如果代理未运行,请单击“查看同步状态”对话框中的“开始”。 该对话框将显示有关验证的信息性消息。
如果看不到有关验证的任何消息,代理已记录后续消息。 在这种情况下,在复制监视器中查看验证结果。 有关详细信息,请参阅本主题中关于复制监视器的操作流程。
使用 Transact-SQL(T-SQL)
在发布者的发布数据库上,执行sp_validatemergepublication(Transact-SQL)。 为@level指定@publication和以下值之一:
- 1 - 仅行计数验证。
- 3 - 行计数二进制校验和验证。
这会将所有订阅标记为待验证。
检查代理输出中是否存在验证结果。 有关详细信息,请参阅 订阅服务器上的“验证数据”。
对于合并发布的单个推送订阅
使用复制监视器
- 在复制监视器中,展开左窗格中的发布者组,展开发布者,然后单击发布。
- 单击“ 所有订阅 ”选项卡。
- 右键单击要验证的订阅,然后单击“ 验证订阅”。
- 在“ 验证订阅 ”对话框中,选择“ 验证此订阅”。
- 若要指定要执行的验证类型(行计数或行计数和校验和),请单击 “选项”,然后在“ 订阅验证选项 ”对话框中指定选项。
- 单击 “确定” 。
- 单击“ 所有订阅 ”选项卡。
- 查看验证结果:
- 如果代理未运行,请右键单击订阅,然后单击“ 开始同步”。
- 右键单击订阅,然后单击“ 查看详细信息”。
- 在所选会话文本区域的“最后一条消息”中查看“同步历史记录”选项卡的信息。
对于合并发布的所有推送订阅
使用复制监视器
- 在复制监视器中,展开左窗格中的发布服务器组,然后展开发布服务器。
- 右击要验证其订阅的发布,然后单击“验证所有订阅”。
- 在“ 验证所有订阅 ”对话框中,指定要执行的验证类型(行计数或行计数和校验和)。
- 单击 “确定” 。
- 单击“ 所有订阅 ”选项卡。
- 查看验证结果。 对于每个推送订阅:
- 如果代理未运行,请右键单击订阅,然后单击“ 开始同步”。
- 右键单击订阅,然后单击“ 查看详细信息”。
- 在所选会话文本区域的“最后一条消息”中查看“同步历史记录”选项卡的信息。
使用合并代理参数验证数据
在订阅服务器(请求订阅)或分发服务器(推送订阅)中通过以下方法之一从命令提示符处启动合并代理。
- 为 -Validate 参数指定值 1(rowcount)或 3(行计数和二进制校验和)。
- 指定 -ProfileName 参数的行计数验证或行计数和校验和验证。
使用复制管理对象 (RMO)
通过复制,可以使用复制管理对象(RMO)以编程方式验证订阅服务器上的数据是否与发布服务器上的数据匹配。 所使用的对象取决于复制拓扑的类型。 事务性的复制需要验证对发布的所有订阅。
注释
有关示例,请参阅本部分后面的 示例(RMO)。
验证事务发布中所有项目的数据
使用 ServerConnection 类创建与发布服务器的连接。
创建 TransPublication 类的一个实例。 设置发布的Name属性和DatabaseName属性。 将 ConnectionContext 属性设置为在步骤 1 中创建的连接。
LoadProperties调用该方法以获取对象的剩余属性。 如果此方法返回
false
,则步骤 2 中的发布属性定义不正确或发布不存在。调用 ValidatePublication 方法。 传递以下内容:
- ValidationOption
- ValidationMethod
- 一个布尔值,指示验证完成后是否停止分发代理。
这将标记用于验证的文章。
如果尚未运行,请启动分发代理以同步每个订阅。 有关详细信息,请参阅 同步推送订阅 或 同步请求订阅。 验证作的结果将写入代理历史记录。 有关详细信息,请参阅 监视复制。
验证合并发布的所有订阅中的数据
- 使用 ServerConnection 类创建与发布服务器的连接。
- 创建 MergePublication 类的一个实例。 设置用于发布的Name属性和DatabaseName属性。 将 ConnectionContext 属性设置为在步骤 1 中创建的连接。
-
LoadProperties调用该方法以获取对象的剩余属性。 如果此方法返回
false
,则步骤 2 中的发布属性定义不正确或发布不存在。 - 调用 ValidatePublication 方法。 传递所需的 ValidationOption。
- 运行每个订阅的合并代理以开始验证,或等待下一个计划的代理运行。 有关详细信息,请参阅 同步请求订阅 和 同步推送订阅。 验证作的结果将写入代理历史记录,使用复制监视器查看该历史记录。 有关详细信息,请参阅 监视复制。
验证合并发布的单个订阅中的数据
- 使用 ServerConnection 类创建与发布服务器的连接。
- 创建 MergePublication 类的一个实例。 设置发布的Name和DatabaseName属性。 将 ConnectionContext 属性设置为在步骤 1 中创建的连接。
-
LoadProperties调用该方法以获取对象的剩余属性。 如果此方法返回
false
,则步骤 2 中的发布属性定义不正确或发布不存在。 - 调用 ValidateSubscription 方法。 传递正在验证的订阅者和订阅数据库的名称及所需的 ValidationOption。
- 运行订阅的合并代理以开始验证,或等待下一个计划的代理运行。 有关详细信息,请参阅 同步请求订阅 和 同步推送订阅。 验证作的结果将写入代理历史记录,使用复制监视器查看该历史记录。 有关详细信息,请参阅 监视复制。
示例(RMO)
此示例将所有订阅标记为用于事务发布的行计数验证。
// Define the server, database, and publication names
string publisherName = publisherInstance;
string publicationName = "AdvWorksProductTran";
string publicationDbName = "AdventureWorks2012";
TransPublication publication;
// Create a connection to the Publisher.
ServerConnection conn = new ServerConnection(publisherName);
try
{
// Connect to the Publisher.
conn.Connect();
// Set the required properties for the publication.
publication = new TransPublication();
publication.ConnectionContext = conn;
publication.Name = publicationName;
publication.DatabaseName = publicationDbName;
// If we can't get the properties for this publication,
// throw an application exception.
if (publication.LoadProperties())
{
// Initiate validataion for all subscriptions to this publication.
publication.ValidatePublication(ValidationOption.RowCountOnly,
ValidationMethod.ConditionalFast, false);
// If not already running, start the Distribution Agent at each
// Subscriber to synchronize and validate the subscriptions.
}
else
{
throw new ApplicationException(String.Format(
"Settings could not be retrieved for the publication. " +
"Ensure that the publication {0} exists on {1}.",
publicationName, publisherName));
}
}
catch (Exception ex)
{
// Do error handling here.
throw new ApplicationException(
"Subscription validation could not be initiated.", ex);
}
finally
{
conn.Disconnect();
}
' Define the server, database, and publication names
Dim publisherName As String = publisherInstance
Dim publicationName As String = "AdvWorksProductTran"
Dim publicationDbName As String = "AdventureWorks2012"
Dim publication As TransPublication
' Create a connection to the Publisher.
Dim conn As ServerConnection = New ServerConnection(publisherName)
Try
' Connect to the Publisher.
conn.Connect()
' Set the required properties for the publication.
publication = New TransPublication()
publication.ConnectionContext = conn
publication.Name = publicationName
publication.DatabaseName = publicationDbName
' If we can't get the properties for this publication,
' throw an application exception.
If publication.LoadProperties() Then
' Initiate validataion for all subscriptions to this publication.
publication.ValidatePublication(ValidationOption.RowCountOnly, _
ValidationMethod.ConditionalFast, False)
' If not already running, start the Distribution Agent at each
' Subscriber to synchronize and validate the subscriptions.
Else
Throw New ApplicationException(String.Format( _
"Settings could not be retrieved for the publication. " + _
"Ensure that the publication {0} exists on {1}.", _
publicationName, publisherName))
End If
Catch ex As Exception
' Do error handling here.
Throw New ApplicationException( _
"Subscription validation could not be initiated.", ex)
Finally
conn.Disconnect()
End Try
该示例标记了一个用于合并发布的特定订阅,以进行行数验证。
// Define the server, database, and publication names
string publisherName = publisherInstance;
string publicationName = "AdvWorksSalesOrdersMerge";
string publicationDbName = "AdventureWorks2012";
string subscriberName = subscriberInstance;
string subscriptionDbName = "AdventureWorks2012Replica";
MergePublication publication;
// Create a connection to the Publisher.
ServerConnection conn = new ServerConnection(publisherName);
try
{
// Connect to the Publisher.
conn.Connect();
// Set the required properties for the publication.
publication = new MergePublication();
publication.ConnectionContext = conn;
publication.Name = publicationName;
publication.DatabaseName = publicationDbName;
// If we can't get the properties for this merge publication, then throw an application exception.
if (publication.LoadProperties())
{
// Initiate validation of the specified subscription.
publication.ValidateSubscription(subscriberName,
subscriptionDbName, ValidationOption.RowCountOnly);
// Start the Merge Agent to synchronize and validate the subscription.
}
else
{
throw new ApplicationException(String.Format(
"Settings could not be retrieved for the publication. " +
"Ensure that the publication {0} exists on {1}.",
publicationName, publisherName));
}
}
catch (Exception ex)
{
// Do error handling here.
throw new ApplicationException(String.Format(
"The subscription at {0} to the {1} publication could not " +
"be validated.", subscriberName, publicationName), ex);
}
finally
{
conn.Disconnect();
}
' Define the server, database, and publication names
Dim publisherName As String = publisherInstance
Dim publicationName As String = "AdvWorksSalesOrdersMerge"
Dim publicationDbName As String = "AdventureWorks2012"
Dim subscriberName As String = subscriberInstance
Dim subscriptionDbName As String = "AdventureWorks2012Replica"
Dim publication As MergePublication
' Create a connection to the Publisher.
Dim conn As ServerConnection = New ServerConnection(publisherName)
Try
' Connect to the Publisher.
conn.Connect()
' Set the required properties for the publication.
publication = New MergePublication()
publication.ConnectionContext = conn
publication.Name = publicationName
publication.DatabaseName = publicationDbName
' If we can't get the properties for this merge publication, then throw an application exception.
If publication.LoadProperties() Then
' Initiate validation of the specified subscription.
publication.ValidateSubscription(subscriberName, _
subscriptionDbName, ValidationOption.RowCountOnly)
' Start the Merge Agent to synchronize and validate the subscription.
Else
Throw New ApplicationException(String.Format( _
"Settings could not be retrieved for the publication. " + _
"Ensure that the publication {0} exists on {1}.", _
publicationName, publisherName))
End If
Catch ex As Exception
' Do error handling here.
Throw New ApplicationException(String.Format( _
"The subscription at {0} to the {1} publication could not " + _
"be validated.", subscriberName, publicationName), ex)
Finally
conn.Disconnect()
End Try