MSSQL复制分发对异构数据库之间大容量数据分发造成异常
由于历史遗留的问题,现有的架构中存在采用MSSQL的复制分发功能,从Oracle发布数据到MSSQL。
关于这项发布的实现原理,官方表述如下:
Oracle 事务发布是通过使用 SQL Server 的事务发布体系结构来实现的;但更改却是通过结合使用 Oracle 数据库上的数据库触发器和日志读取器代理来跟踪的。Oracle 事务发布的订阅服务器使用快照复制自动进行初始化;在以后发生更改时,将通过日志读取器代理对这些更改进行跟踪,并将更改传递到订阅服务器。
创建 Oracle 发布时,将为 Oracle 数据库中所有已发布的表创建触发器和跟踪表。对发布的表进行数据更改时,将激发这些表的数据库触发器,并在复制跟踪表中为修改的每一行插入信息。然后,SQL Server 分发服务器上的日志读取器代理将数据更改信息从跟踪表移动到分发服务器上的分发数据库中。最后,与在标准事务复制中一样,分发代理将更改从分发服务器移动到订阅服务器。
详细内容,请点击查看。
需要注意的是:
1、大型对象 (LOB) 数据并不存储在项目日志表中,LOB 数据的更新始终是从已发布的表中直接检索的。 只有当影响 LOB 的操作激发了复制的表上的复制触发器时,才会在事务性发布中复制更新。 插入或删除包含 LOB 的行时,将激发 Oracle 触发器;但更新 LOB 列并不会激发触发器。 只有在同一 Oracle 事务中同时更新同一行的 LOB 列和非 LOB 列时,才会立即复制 LOB 列的更新。 否则,只有在下一次更新该行中的非 LOB 列时,才会刷新订阅服务器中的 LOB 列。 请确保您的应用程序可以接受此行为。
2、在 MicrosoftSQL Server 分发服务器上安装 Oracle 客户端软件和 OLE DB 访问接口,然后重新启动 SQL Server 实例。如果分发服务器运行在 64 位平台上,则必须使用 64 位版本的 Oracle OLE DB 访问接口。
3、在发布服务器上创建的各种表所代表的含义
对象名 |
对象类型 |
说明 |
---|---|---|
HREPL_ArticleNlog_V |
表 |
更改跟踪表,当对已发布的表中进行了更改时,可使用此表存储更改信息。 为每个已发布的表创建一个更改跟踪表。 |
HREPL_Changes |
表 |
Xactset 作业内部用来确定等待分配给事务集的更改数量的表。 有关此作业的详细信息,请参阅Oracle 发布服务器性能优化。 |
HREPL_Distributor |
表 |
分发服务器状态表,用于维护与 Oracle 发布服务器相关联的 SQL Server 分发服务器的信息。 |
HREPL_Event |
表 |
事件表,用于同步快照和行计数请求。 |
HREPL_Mutex |
表 |
用于确保 Oracle 包过程 PopulatePollTable 未由日志读取器代理和数据库作业并发执行的表。 |
HREPL_Poll |
表 |
用于标识与几组已发布表的更改相关联的日志表项的表。 |
HREPL_PublishedTables |
表 |
包含事务性发布中每个项目项的表。 |
HREPL_Publisher |
表 |
发布服务器状态表,用于维护发布服务器的特定信息。 |
HREPL_SchemaFilter |
表 |
包含在通过新建发布向导发布时不显示的架构的表。 |
HREPL_XactsetCreateTimes |
表 |
标识与每个事务集相关联的创建时间的表。 |
HREPL_XactsetJob |
表 |
包含用于 Xactset 作业的当前参数设置的表。 |
HREPL_Pollid |
序列 |
用于生成轮询 ID 的序列。 |
HREPL_Seq |
序列 |
用于对更改命令进行排序的序列。 |
HREPL_Stmt |
序列 |
用于生成语句 ID 的序列。 |
HREPL |
包和包正文 |
在发布服务器上创建的发布服务器支持代码的包。 |
MSSQLSERVERDISTRIBUTOR |
公共同义词 |
HREPL_Distributor 表的公共同义词。 如果将分发服务器配置为与 Oracle 发布服务器一起使用,而且此同义词已存在于数据库中,则应将其删除并重新创建。 用 CASCADE 选项删除公共同义词和已配置的 Oracle 复制用户会删除 Oracle 发布服务器中的所有复制对象。 |
HREPL_Len_I_J_K |
函数 |
在 Oracle 发布包代码之外定义的、用于查询 LONG 列的长度(在为带有已发布 LONG 列的表生成参数化命令时使用)的函数。 为每个带有 LONG 列的已发布表创建一个函数。 |
HREPL_DropPublisher |
过程 |
在 Oracle 发布包代码之外定义的、用于删除 Oracle 发布服务器的过程。 |
HREPL_ExecuteCommand |
过程 |
在 Oracle 发布包代码之外定义的、用于在发布服务器上执行命令的过程。 |
HREPL_ArticleN_Trigger_Row |
触发器 |
为每个已发布表生成的、用于跟踪行更改的触发器。 |
HREPL_ArticleN_Trigger_Stmt |
触发器 |
为每个已发布表生成的、用于跟踪语句级更改的触发器。 |
HREPL_Article_I_J |
视图 |
为每个已发布表创建的、用于查询已发布表的视图。 |
HREPL_Log_I_J_K |
视图 |
为每个已发布表创建的、用于查询更改跟踪表的视图。 |
遇到的问题:
当在发布服务器上更新了超过100万行的记录时,就会导致这台发布服务器上的所有项目都会出错。 据我在处理过程中的总结,估计是代理服务器无法读取这么大量的数据,或者是因为读取这么大量的数据,导致超时。
处理方法:
步骤一、先到复制监视器找到此发布服务器下的代理,停止“日志读取器代理”。若是停止之后,就直接重新启动,会一直显示初始化,最后的结果还是初始化不能成功。
步骤二、到Oracle发布服务器上找到元凶
- --动态生成拼接语句
- SELECT 'SELECT ''' || OBJECT_NAME || ''' TABLE_NAME , COUNT(1) CNT FROM PUB.' || OBJECT_NAME || ' UNION'
- FROM dba_objects
- WHERE owner = 'PUB' AND OBJECT_TYPE = 'TABLE' AND OBJECT_NAME LIKE '%ARTICLE%' OR OBJECT_NAME LIKE '%HREPL_POLL%';
- --对拼接结果进行查询
- SELECT *
- FROM (
- SELECT 'HREPL_ARTICLE29LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE29LOG_1 UNION
- SELECT 'HREPL_ARTICLE28LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE28LOG_1 UNION
- SELECT 'HREPL_ARTICLE19LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE19LOG_1 UNION
- SELECT 'HREPL_ARTICLE21LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE21LOG_1 UNION
- SELECT 'HREPL_ARTICLE22LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE22LOG_1 UNION
- SELECT 'HREPL_ARTICLE23LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE23LOG_1 UNION
- SELECT 'HREPL_ARTICLE24LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE24LOG_1 UNION
- SELECT 'HREPL_ARTICLE25LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE25LOG_1 UNION
- SELECT 'HREPL_POLL' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_POLL UNION
- SELECT 'HREPL_ARTICLE39LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE39LOG_1 UNION
- SELECT 'HREPL_ARTICLE45LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE45LOG_1 UNION
- SELECT 'HREPL_ARTICLE43LOG_1' TABLE_NAME , COUNT(1) CNT FROM PUB.HREPL_ARTICLE43LOG_1
- )
- ORDER BY CNT DESC ;
步骤三:把表名包含“ARTICLE数字LOG”且行记录超过100W行的表清空(例如:我这次处理的就是“HREPL_ARTICLE45LOG”);
特别说明:这样做是无奈之举,为了挽救在此发布服务器上的其他项目,把损失降低到最低。这样做,会造成包含清空表所依赖的的发布和订阅两边的数据不一致,最后可能还是需要重新初始化此发布项目。
- --查看发布的原表
- SELECT D1.owner
- , D1.name
- , D1.type
- , D1.referenced_owner
- , D1.referenced_name
- , D2.referenced_owner
- , D2.referenced_name
- FROM DBA_DEPENDENCIES D1
- JOIN DBA_DEPENDENCIES D2 ON D1.owner = D2.owner AND D1.name = D2.name
- WHERE D1.REFERENCED_NAME = 'HREPL_ARTICLE45LOG_1'
- AND D1.TYPE = 'TRIGGER'
- AND D1.REFERENCED_OWNER <> D2.REFERENCED_OWNER
- AND D2.REFERENCED_OWNER NOT IN ('SYS','PUBLIC') ;
- --清空数据
- TRUNCATE TABLE mbs7_pub.HREPL_ARTICLE45LOG_1 ;
- --把情况表对应的poll内的记录也清空
- DELETE FROM mbs7_pub.HREPL_POLL WHERE poll_tableid = 45 ; --这里的tableid是和上面语句的“ARTICAL”后面的数字对应的
步骤四、重新启动MSSQL复制监视器中的“日志读取器代理”。
注:此时可以看到复制分发是正常的,但是,如上文所有,这样做在某个时候导致数据不一致,相当于埋了一个定时炸弹。所以,要在一个相对空闲的时间,把这个项目重新初始化一次,保证数据的一致性。
更稳妥的解决是:
尽量把大事务拆分一下,保证每次的操作记录少于100万,建议设置得更低一点。
以上,如有纰漏,请不吝指正,若有更好的建议,请不吝指教。
MSSQL复制分发对异构数据库之间大容量数据分发造成异常的更多相关文章
- SQLite与MySQL、SQLServer等异构数据库之间的数据同步
SQLite DBSync是开源嵌入式数据库SQLite的数据同步引擎,实现了SQLite与SQLite数据库之间以及SQLite与异构数据库(Oracle.MySQL.SQLServer)之间的增量 ...
- (转载)异构数据库之间完全可以用SQL语句导数据
<来源网址:http://www.delphifans.com/infoview/Article_398.html>异构数据库之间完全可以用SQL语句导数据 告诉你一个最快的方法,用SQL ...
- 异构数据库之间完全可以用SQL语句导数据
告诉你一个最快的方法,用SQLServer连接DBF 在SQLServer中执行 SELECT * into bmk FROM OpenDataSource( ‘Microsoft.Jet.OLEDB ...
- SQL Server 之 在数据库之间进行数据导入导出
1.同一服务器上数据库之间进行数据导入导出 (1).使用 SELECT INTO 导出数据 在SQL Server中使用最广泛的就是通过SELECT INTO语句导出数据,SELECT INTO语句同 ...
- 阿里云RDS实例内不同数据库之间的数据迁移
适用场景 本文适用于使用DTS实现相同实例下库名不同的数据库之间的数据迁移.本文以使用DTS将同一RDS实例下的amptest库迁移到jiangliu_amptest库为例来说明如何使用DTS实现相同 ...
- SQL不同服务器数据库之间的数据操作整理(完整版)
---------------------------------------------------------------------------------- -- Author : htl25 ...
- SQLServer服务器数据库之间的数据操作(完整版)
分类: 数据库开发技术 ---------------------------------------------------------------------------------- -- Au ...
- 转载-SQL不同服务器数据库之间的数据操作整理(完整版) .
---------------------------------------------------------------------------------- -- Author : htl25 ...
- C#实现两个数据库之间的数据上报
用VS2008实现本地数据库上传数据到远程数据.数据能够是一个表,或一个表的部分数据.或查询数据.或数据编辑后上传. 其他VS版本号.复制当中代码就能够.未使用其他不论什么插件.有具体凝视. 单独页面 ...
随机推荐
- .net mvc 框架实现后台管理系统 2
layui 数据表格 返回格式: var json = new { code = 0, count = pagers.totalRows, msg = "", data =null ...
- Qt 学习之路 2(1):序
https://www.devbean.net/category/qt-study-road-2/page/10 原来开过QT学习之路1, 很棒, 再翻阅时已经没有了. 所以这次把看过的记录下来 Ho ...
- react 中文文档案例六 (表单)
class Reservation extends React.Component { constructor(props) { super(props); this.state = { isGoin ...
- ul li做横向导航栏例子
/* ul li以横排显示 */ /* 所有class为menu的div中的ul样式 */ div.menu ul { list-style:none; /* 去掉ul前面的符号 */ margin: ...
- python 基础及if while for语句
#####变量######一.命名规则 1.正常命名 可以由字母,下划线和数字组成,不能以数字开头,不能和关键字重明 2.驼峰命名法 1)大驼峰:每一个单词的首字母都大写 Fi ...
- Linux多线程及线程同步简单实例
一.多线程基本概念 1. 线程的基本概念 ① 线程就是轻量级的进程 ②线程和创建他的进程共享代码段.数据段 ③线程拥有自己的栈 2. 在实际应用中,多个线程往往会访问同一数据或资源,为避免线程之间相互 ...
- CSS background-size contain 与cover的区别
最近在重温CSS,发现好多东西都忘了,比如background-size属性中,contain与cover的区别. 菜鸟教程上是这么说的: 有点难理解,通俗解释就是:两者均以保持图像宽高比的形式缩放来 ...
- JS图片加载失败用默认图片代替
1.onerror 事件会在文档或图像加载过程中发生错误时被触发. 当图片不存在时,将触发onerror,onerror 中img为 指定的默认图片. 图片存在则显示正常图片,图片不存在将显示默认. ...
- mapreduce统计总数
现有某电商网站用户对商品的收藏数据,记录了用户收藏的商品id以及收藏日期,名为buyer_favorite1. buyer_favorite1包含:买家id,商品id,收藏日期这三个字段,数据以“\t ...
- 配置MapReduce程序运行环境
已安装eclipse,hadoop 查看教程dblab.xmu.edu.cn/blog/hadoop-build-project-using-eclipse/