eXtremeDB通过JDBC从oracle中导入数据
2014-12-07 13:10
169 查看
eXtremeDB通过JDBC从oracle中导入数据。
开始使用了单线程导入,速度非常慢。3.5亿条数据,大概需要1天的时间,换成两台服务器组成eXtremeDB的sharding后,时间变成了2天。
于是开始尝试多线程导入。
可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字句中限制天数了。月分区估计就不能合理切分数据了。
于是我在把分区信息加入队列的时候,会先count一下每个分区的数据数量
select count(1) from xx_table partition(20100101)
然后按照数据量的大小顺序加入队列。
这样,线程就会优先处理数据量大的分区,数据量小的分区放在最后处理,达到最佳的并发效果。
进一步对代码进行优化,使用了生产者消费者模式。
在java中,对这种模式有一个非常棒的类:BlockingQueue
使用这种模式后,多个线程从oracle导数据,插入到BlockingQueue中。
多个线程从BlockingQueue中读取数据,插入到eXtremeDB。
通过使用此模式,既优化了读取和插入的速度不对称问题,又最大程度上实现了高并发(避免个别分区导入时间长,拖累整体导入时间,也就是可以省略掉上一步依据数据量的优化)
开始使用了单线程导入,速度非常慢。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。
通过使用此模式,既优化了读取和插入的速度不对称问题,又最大程度上实现了高并发(避免个别分区导入时间长,拖累整体导入时间,也就是可以省略掉上一步依据数据量的优化)
相关文章推荐
- (七) solr数据导入:通过JDBC从数据库导入数据
- 通过批处理来完成oracle的数据导入导出及备份工作
- oracle impdp通过network_link不落地方式导入数据
- FLEX中的MXML通过JDBC连接ORACLE读取相关数据
- Oracle:通过oracle sql developer工具导入excel数据
- Excel数据通过plsql导入到Oracle
- oracle通过impdp导入不同表用户、不同表空间的数据
- Oracle impdp通过network_link不落地方式导入数据
- 将excel数据通过plsql导入oracle的问题
- oracle impdp通过network_link不落地方式导入数据
- oracle通过impdp导入不同表用户、不同表空间的数据
- Excel数据通过plsql 导入到Oracle
- Oracle impdp通过network_link不落地方式导入数据
- 通过SSIS设计ETL来将Oracle/DB2/Sybase等数据源的数据定期导入到数据仓库(一)
- Oracle通过PL/SQL数据泵导出导入数据的命令
- 通过SSIS设计ETL来将Oracle/DB2/Sybase等数据源的数据定期导入到数据仓库(二)
- Oracle读取Blob数据-通过JDBC
- 教你Excel数据通过plsql导入到Oracle
- 如何通过pl/sql将excel文件数据导入到oracle
- oracle通过ociuldr导入平面文件数据。