您的位置:首页 > 数据库 > Oracle

eXtremeDB通过JDBC从oracle中导入数据

2014-12-07 13:10 169 查看
eXtremeDB通过JDBC从oracle中导入数据。

开始使用了单线程导入,速度非常慢。3.5亿条数据,大概需要1天的时间,换成两台服务器组成eXtremeDB的sharding后,时间变成了2天。

于是开始尝试多线程导入。

最大的问题:对数据的切分

多线程导入,首先考虑怎样切分数据。

rownum 切分

最开始,想到了rownum,用oracle的rownum,把数据切分成几块,每个线程处理其中一块。
可rownum只能参与小于运算,不能参与大于运算。
比如 where rownum <=1000 是对的
rownum <= 1000 and rownum >= 500就是错误的。
因为rownum是一个总是从1开始的伪列,

所以要用rownum进行数据切分,只能使用一个双层的select 语句,内层把全部数据分配rownum,并取别名。
然后在外层对rownum进行切分。
可这样的双层select 语句,是非常非常慢的。
通过这样的数据切分,追踪运行多线程程序,甚至可能还不如单线程快。

以分区切分

于是又想到了按天切分,本来打算是
where timeXX <= 某天 and timeXX >=某天
可发现要导入的oracle表,是一个分区表,表中的数据是以天为单位分区的。
那我们恰好可以以分区为单位导入数据了,这样连where字句都可以省略掉,可以达到性能的最大化。
于是我建了一个队列,里面存储了这张分区表的全部分区。
全部线程不断的从队列中取分区名称,来进行数据的加载。
每个线程执行的selec语句如下:
select * from xx_table partition(20100101) //此场景下,分区的名字是以日期命名的,如20100101
这条连where字句都省略掉的select语句,速度应该已经是最快的了。
本来还想着在select语句中加入/*parallel 2*/ 并发查询,但因为我已经同时开了32个线程同时在oracle中查询了,意义已经不大。
如果以后的表结构不是以天分区,而是以星期分区,也可以考虑这样导入数据。
如果是以月分区的,那就只能考虑在where字句中限制天数了。月分区估计就不能合理切分数据了。

进一步优化:

我开启了32个线程同时导入数据,可我发现当大多数线程结束(线程导入完毕一个分区的数据,检测到存放分区信息的队列已经为空后,会结束),总有那么一两个线程依然在长时间的运行,最终导致导入时间整体过长。
于是我在把分区信息加入队列的时候,会先count一下每个分区的数据数量
select count(1) from xx_table partition(20100101)

然后按照数据量的大小顺序加入队列。
这样,线程就会优先处理数据量大的分区,数据量小的分区放在最后处理,达到最佳的并发效果。

再进一步优化:

考虑到从oracle导出、对eXtremeDB插入操作的速度不对称问题。(因为eXtremeDB是纯内存数据库,加上使用了sharding,插入速度是微秒级,极快的)
进一步对代码进行优化,使用了生产者消费者模式。
在java中,对这种模式有一个非常棒的类:BlockingQueue
使用这种模式后,多个线程从oracle导数据,插入到BlockingQueue中。
多个线程从BlockingQueue中读取数据,插入到eXtremeDB。
通过使用此模式,既优化了读取和插入的速度不对称问题,又最大程度上实现了高并发(避免个别分区导入时间长,拖累整体导入时间,也就是可以省略掉上一步依据数据量的优化)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: