原文:SQL Server 事务复制分发到订阅同步慢

最近发现有一个发布经常出现问题,每几天就出错不同步,提示要求初始化。重新调整同步后,复制还是很慢!每天白天未分发的命令就达五六百万条!要解决慢的问题,需要了解从发布数据库到订阅数据库中,有哪些操作,才知道哪个步骤同步缓慢。

这是很久之前自己做的一张图,主要描述发布到分发、分发到订阅中,复制使用了哪些操作,如下图:

发布到分发:

在发布中,复制是使用日志读取器读(sp_replcmds)取发布数据库中的事务日志的,日志读取器是按事务顺序读取的,所以每个数据库只能有一个(若有CDC也使用同一个日志读取器)。

首选,在事务日志中,到底有多少是需要复制的?使用以下命令,可以确定事务日志中被标志为复制的命令有多少。

USE <publisher_database>
GO
SELECT count(*) FROM ::fn_dblog(NULL, NULL) WHERE Description='REPLICATE'
GO

如果事务日志中标志为复制的命令很多,常见的种情况有:

1. 有一个较大的事务还没读取到;

2. 日志读取器出现问题;

正常来说,日志读取器扫描日志还是比较快的,不会有什么问题,不会累计较多待读取的日志。可以使用性能计数器监控日志读取器读取情况:

"\SQLServer:Replication Logreader\Logreader:Delivered Cmds/sec"

"\SQLServer:Replication Logreader\Logreader:Delivered Trans/sec"

日期读取器读取事务日志后,会通过存储过程 sp_msadd_commands 写入到分发服务器上的分发数据库  distribution 。但是写入是否正常呢?从上面计数器跟踪的情况,可以估计每分钟有读取了多少命令。需要分发的事务和命令,系统存储过程分别写入了分发库上的表 MSrepl_transactions和 MSrepl_commands
,这两个表记录了需要分发的命令(注意:其中的命令可能已经分发到订阅了,只是还没清除)。将两表关联按分钟统计,可以确定每分钟写入到分发库上的命令有多少了。

SELECT
DATEPART(mm, [entry_time]) 'month',
DATEPART(dd, [entry_time]) 'day',
DATEPART(hh, [entry_time]) 'hour',
DATEPART(MI, [entry_time]) 'Minute',
COUNT(C.[xact_seqno]) 'count of commands'
FROM [dbo].[MSrepl_transactions](nolock) T
INNER JOIN [dbo].[MSrepl_commands](nolock) C
ON T.[xact_seqno] = C.[xact_seqno]
AND T.publisher_database_id=c.publisher_database_id
WHERE [entry_time] >='2017-05-04 12:00:00'
GROUP BY DATEPART(mm, [entry_time]),
DATEPART(dd, [entry_time]),
DATEPART(hh, [entry_time]),
DATEPART(MI, [entry_time])
ORDER BY 1, 2, 3,4
GO

在发布到分发中,事务命令的读取和写入可做对比,确定读或写是哪段出现问题。

分发到订阅:

分发到订阅,首选确定有多少命令是需要分发的,若直接求和  MSrepl_transactions 和 MSrepl_commands是不准确的,因为有的已经分发了。可以打开复制监视器查看某个发布中未分发的命令,若用脚本查看,有两个方法:

/************************方法一****************************/
EXEC distribution.sys.sp_replmonitorsubscriptionpendingcmds
@publisher = N'发布服务器名称'
, @publisher_db = N'发布数据库名称'
, @publication = N'发布名称'
, @subscriber = N'订阅服务器名称'
, @subscriber_db = N'订阅数据库名称'
, @subscription_type =1
go /************************方法二****************************/
--未分发的事务数
With MaxXact (ServerName, PublisherDBID, XactSeqNo)
As (Select S.name, DA.publisher_database_id, max(H.xact_seqno)
From distribution.dbo.MSdistribution_history H with(nolock)
Inner Join distribution.dbo.MSdistribution_agents DA with(nolock) On DA.id = H.agent_id
Inner Join master.sys.servers S with(nolock) On S.server_id = DA.subscriber_id
Group By S.name, DA.publisher_database_id)
Select MX.ServerName, MX.PublisherDBID, COUNT(*) As TransactionsNotReplicated
From distribution.dbo.msrepl_transactions T with(nolock)
Right Join MaxXact MX On MX.XactSeqNo < T.xact_seqno And MX.PublisherDBID = T.publisher_database_id
Group By MX.ServerName, MX.PublisherDBID;
GO
--未分发的命令数
With MaxXact (ServerName, PublisherDBID, XactSeqNo)
As (Select S.name, DA.publisher_database_id, max(H.xact_seqno)
From distribution.dbo.MSdistribution_history H with(nolock)
Inner Join distribution.dbo.MSdistribution_agents DA with(nolock) On DA.id = H.agent_id
Inner Join master.sys.servers S with(nolock) On S.server_id = DA.subscriber_id
Group By S.name, DA.publisher_database_id)
Select MX.ServerName, MX.PublisherDBID, COUNT(*) As CommandsNotReplicated
From distribution.dbo.MSrepl_commands C with(nolock)
Right Join MaxXact MX On MX.XactSeqNo < C.xact_seqno And MX.PublisherDBID = C.publisher_database_id
Group By MX.ServerName, MX.PublisherDBID;
GO

总体监控分发到订阅的情况,可以使用计数器跟踪:

"\SQLServer:Replication Dist\Dist:Delivered Cmds/sec"

"\SQLServer:Replication Dist\Dist:Delivered Trans/sec"

若了解更详细情况,可在分发代理中添加以下参数,重启分发作业。

-Output [output_path_and_file_name]

-OutputVerboseLevel [0|1|2]]

接下来回归主题:SQL Server 事务复制分发到订阅同步慢

当前未分发的命令已经堵了六百多万条了,而分发差不多两分钟才分发一次。在分发数据库中查看当前执行了什么命令,经常看到在执行存储过程
sp_MSget_repl_commands ,该存储过程是从  MSrepl_transactions 和 MSrepl_commands 读取未分发的命令,将这些命令应用到订阅中。但是读取出现了等待类型ASYNC_NETWORK_IO
,ASYNC_NETWORK_IO  意思是数据已经读取了,但是客户的还没有完全把数据拿走。按正常理解,这些这个等待类型,很可能是网络问题。

为了确定是不是网络问题,我用了以下方法:

1.  从其他不堵塞的发布中,插入跟踪器。确认整个过程网络没什么问题。

2. ping 网络,看时间多少。基本1ms 内,正常!

3. 订阅中创建一个共享文件夹,在分发服务器访问共享,拷贝一个大文件过去。拷贝速度66mb/s ,没毛病!

既然网络没什么问题,那就要确定是不是分发到订阅中 “写” 出现了问题?到订阅服务器查看当前执行了什么命令,发现一个命令总数一直在执行!

从缓存中,查看执行情况,发现该存储过程耗时非常多!

SELECT TOP 25
st.text, qp.query_plan,
(qs.total_logical_reads/qs.execution_count) as avg_logical_reads,
(qs.total_logical_writes/qs.execution_count) as avg_logical_writes,
(qs.total_physical_reads/qs.execution_count) as avg_phys_reads,
qs.*
FROM sys.dm_exec_query_stats as qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) as qp
WHERE st.text like '%sp_MSupd_dboMDS_ADRelation%'
ORDER BY qs.total_worker_time DESC
Go

点击上面查询出来的执行计划,发现应用的表竟然用表扫描!!!

找到表 MDS_ADRelation ,发现竟然没有主键(或索引)!!

表发布订阅是必须有主键的,订阅也会一会保留主键的,数据的同步更新就是按主键做条件进行更新的,而表主键没了,更新就用不上索引了!!真不知道是谁删除的!

从发布中把创建主键的脚本导出来,到订阅执行,因为同步正在进行,创建主键时使用 (online=on)在线创建。创建完成后,分发瞬间加快(如下图),订阅中流量也瞬间加大了!!复制终于正常了!!

SQL Server 事务复制分发到订阅同步慢的更多相关文章

  1. SQL Server 2012 复制(发布订阅的研究)

    原文:SQL Server 2012 复制(发布订阅的研究) 已实现发布订阅功能,可以实现局域网内双击备份. 一.注意事项: a) 使用[事务复制]功能 b) 必须是相同的SqlServer 帐号和密 ...

  2. SQL Server 事务复制爬坑记

    SQL Server 复制功能折腾了好几天了,现特将其配置过程以及其间遇到的问题记录下来,以备日后查阅.同时,也让“同道”同学们少走不必要的弯路.如果有不对之处,欢迎大家指正,欢迎沟通交流. 一.复制 ...

  3. SQL Server事务复制搭建与同步经验

    0. 环境 无域环境 发布服务和分发服务器同一台主机 角色 主机名 IP 发布名 发布库名/订阅库名 发布服务器 Server1 192.168.1.100 test3 db1 分发服务器(与发布服务 ...

  4. SQL Server事务复制(sql 2008 r2)

    一.环境准备 1.两个虚拟服务器 主机1:XINXIBU01  作为发布和分发服务器   主 机2:XINXIBU02 192.168.1.160  作业阅服务器 2.SQL SERVER sql 2 ...

  5. [20170706]SQL Server事务复制订阅端,job不小心被删,修复

    右击还存在的订阅,生成脚本,有个过程sp_addpullsubscription_agent 执行,发现报错说distribution agent 已经存在 执行: UPDATE dbo.MSrepl ...

  6. 【数据库-Azure SQL Database】如何创建事务复制将本地数据同步到 SQL Azure

    Azure SQL DB 可以被配置成为 SQL Server 事务复制的一个订阅者( subscriber ). 主要应用场景有两种: 将您的数据迁移到 Azure SQL DB, 并且没有宕机时间 ...

  7. SQL Server 2008 R2的发布订阅配置实践

    纸上得来终觉浅,绝知此事要躬行.搞技术尤其如此,看别人配置SQL SERVER的复制,发布-订阅.镜像.日志传送者方面的文章,感觉挺简单,好像轻轻松松的,但是当你自己去实践的时候,你会发现还真不是那么 ...

  8. sql server 本地复制订阅 实现数据库服务器 读写分离(转载)

    转载地址:http://www.cnblogs.com/echosong/p/3603270.html 再前段echosong 写了一遍关于mysql 数据同步实现业务读写分离的文章,今天咱们来看下S ...

  9. sql server 本地复制订阅 实现数据库服务器 读写分离

    再前段echosong 写了一遍关于mysql 数据同步实现业务读写分离的文章,今天咱们来看下SQL Server的复制订阅实现数据的读写分离 比起mysql的复制,SQL server 复制相对强大 ...

随机推荐

  1. js如何使用正则表达式验证电话号码(可选区号)和邮箱?(分步骤)

    js如何使用正则表达式验证电话号码(可选区号)和邮箱?(分步骤) 一.总结 js进阶正则表达式16电话号码和邮箱正则(分类解决邮箱验证)(分组加?解决电话号码区号选择问题)([\w\.-]中括号解决邮 ...

  2. 使用Boolean类型同步锁引起异常的分析

    原文地址 http://topic.csdn.net/u/20080710/19/f61cb4db-ddff-4457-a26a-4ea578b0cc6c.html?87447500 http://w ...

  3. Java之泛型<T> T与T的用法

    <T> T表示返回值是一个泛型,传递啥,就返回啥类型的数据,而单独的T就是表示限制你传递的参数类型,这个案例中,通过一个泛型的返回方式,获取每一个集合中的第一个数据, 通过返回值<T ...

  4. centos安装启动ssh服务

    centos安装启动ssh服务 #rpm -qa |grep ssh 检查是否装了SSH包 没有的话yum install openssh-server #chkconfig --list sshd ...

  5. Ubuntu下一个python的BeautifulSoup和rsa安装方法---信息检索project2部分:微博爬行要求python包裹

    后果<信息检索>第二project,微博具有抓取数据,再处理.师兄给了代码.让慢慢爬.可是在ubuntu下.少了非常多python软件包.须要安装. 1.首先执行时.说少了python.B ...

  6. XCode5.1.1怎样实现代码块自己主动排版

    1.问题描写叙述 在开发中常常遇到代码块须要排版的情况,假设一行一行缩进就太out了,但在xcode中怎样实现还真不知道 2.解决方法 2.1选中须要排版的代码块 2.2单击"Editor ...

  7. C语言笔试题精选3---死锁发生必要条件是?

    问:以下哪些是死锁发生必要条件? A.相互排斥条件 B.请求和保持 C.不可剥夺 D.循环等待 具体解答: 1.相互排斥使用(资源独占)  一个资源每次仅仅能给一个进程使用 2.不可强占(不可剥夺) ...

  8. Java8初体验(二)Stream语法详解---符合人的思维模式,数据源--》stream-->干什么事(具体怎么做,就交给Stream)--》聚合

    Function.identity()是什么? // 将Stream转换成容器或Map Stream<String> stream = Stream.of("I", & ...

  9. 在WSL中安装和运行Docker CE

    安装环境 Windows 10 64bit 专业版 1809 WSL安装ubuntu 18.04 LTS DOCKER安装 安装过程没有什么问题,安装docker的网站说明进行安装https://do ...

  10. SpringCloud学习笔记-zuul网关

    公司目前使用的是dubbo方式实现微服务,想试水改造接口层服务为Spring Cloud, 以下是网络拓补图. 第一层负载均衡可以用nginx或者zuul(即有2层zuul), 本图画的是nginx. ...