因为项目的升级,数据库从oracle改到了sqlserver,这样带来的问题是需要做个移行工具,将Oracle的数据移植到Sqlserver,按照一般的想法,在sqlserver端建一个dblink,连接oracle,insert...select的方式进行数据插入,就解决了,但是事情没有那么简单,接下来将实现过程中遇到的问题,以及如何排雷,最终完美实现的过程说明下,我想对有这方面需求的朋友,一定有所帮助
背景:
小数据量的表,图形化的移行工具,不适合复杂的工厂环境,不在讨论范围。
网上能看到的案是修改max server memory的值,都没法解决。另外修改max server memory的值需要重启SQLSERVER服务,实际的客户现场是不可能这么实现。
我们讨论大数据量表移行,有一个操作log表,数据600多万件,占内存3G多,从oracle中将操作log表中的数据,导入到Sqlserver的操作log表。服务器内存16G。
在Oracle数据库之间,600万件数据的插入是没有问题的,但是往Sqlserver插入,就会出现内存溢出。
案1:创建dblink,dblink..表名的方式访问
INSERT SqlServer表 Select * from OracleLink..LDBTLOGT 16G内存,处理了30万件时内存超了,现象就是内存一直增长,在剩余内存不多时,它会自动回收几次,但是最终还是会内存溢出
案2:dblink..表名的方式访问,每次插入件数指定
使用sqlserver offset,每1000件取一次,进行插入,没有改善,内存还是一直增长。原因在案3说明
案3:使用OPENQUERY代替OracleLink..的DBLink的使用方法
INSERT Sqlserver表 SELECT * FROM OPENQUERY(OracleLink,'select * from Oracle表)
OracleLink是dblink ,内存还是一直增长。
※这里说明下,为什么使用OPENQUERY代替OracleLink..,通过执行计划大家可以看到区别
使用OPENQUERY和OracleLink..的区别,OPENQUERY是直接连接远程的oracle数据库,OracleLink..是从oracle取回来,本地过滤,所以指定件数不起作用
案4:使用OPENQUERY,同时通过oracle的rownum对数据范围进行分割,每处理一次,内存能够释放,600万处理后,内存回收正常
INSERT INTO LDBTLOGT ( SELECT * FROM OPENQUERY(OracleLink,'select Oracle字段 FROM (SELECT Oracle字段,rownum num FROM LDBTLOGT) t2 WHERE t2.num between $BEGINNUM and $ENDNUM'))
总结
为什么在Oracle没有问题,在Sqlsever会出现内存溢出的问题。我认为有2点原因:
1)Sqlserver的内存使用策略:
对于sqlserver数据库什么时候回收内存是系统自己来做的,我们无法来干预。并且Sqlserver的内存使用策略是最大化利用内存,也就是有多少用多少,留有余地太小了,是不是像败家子。我试过将物理内存升到32G,它还是会将内存使用到31G多,然后再释放调整,最终溢出。Sqlserver这方面和Oracle还是没法比。
2)DBLink的内部机制不同
要使用OPENQUERY的方式调用dblink,而不要使用dblink..的方式,原因上面的执行计划可以看出来,使用dblink..的方式,相当于从远程将所有的数据取到本地后,再进行件数过滤。是不是感觉这种方式就不应该存在。
通过案4,内存溢出的问题得到了解决,接下来遇到执行时间太慢的问题,请继续关注