【Oracle】准实时大规模数据提取(oracle 提取小时)
sinye56 2024-10-04 10:57 3 浏览 0 评论
文中使用的Oracle版本为10g。
这篇文章是之前本人在公司内部做可行性分析报告中的其中一个板块的内容,具体讲述的是为了做大规模数据提取和数据清洗做了一个试验demo。先说结论,一般来说像这种操作不应优先考虑关系型数据库去解决。本文中提到的采用Job模拟多线程操作的方式只是不得已而为之,请各位看官慎用。
前因
需要将数据库中表(190+)按照人员编码和业务发生时间进行汇总和排序,得到用户在某时间内的所有操作行为。一般情况下想到使用UNION ALL连接后去重排序,但实际上会面临以下6个问题:
- 需要数据提取的表目前有197个且以后还会随着业务增长而增加(不要问为什么这样设计,别人项目管不了);
- 表中数据都是千万级或者亿级,查询获取数据量大;
- 数据获取动作要求准实时,也就是说在用户触发后需要短时间内获得反馈结果;
- 服务器性能低,基本上不存在系统调优的情况;
- 数据库表不能进行改造,会有别的项目直接访问这些表(不能理解知道为什么允许这样做);
- Java后台程序尽量保持良好的可读性;
基于上述的情况,其实不难分析出:
- 表个数不固定,所以功能必须是可动态配置的;
- 大量的表和大量的数据获取,在SQL语句上不能直接使用UNION ALL操作。需要考虑到可执行SQL 语句长度会受到限制。譬如,每一个表SQL查询格式将会是
select 字段a,字段b,字段c,字段d,字段e,字段f
from 表名
where gather_person = 'gather_person内容'
and gather_date between to_date('开始时间','yyyy-mm-dd HH24:MI:SS')
and to_date('结束时间','yyyy-mm-dd HH24:MI:SS');
这里通过WHERE条件缩小表数据查询范围,在得到数据集后再进行UNION ALL其他数据集操作。但是这197个表下来这个SQL语句将非常庞大。运行起来会占用大量的CPU和内存资源。
其次,即使是使用了UNION ALL连接数据库也是采取串行的查询方式,对于速度提升没有太大帮助,因此使用UNION ALL的方案先按下不表。
既然不能通过一次查询得到结果,那就采用分步获取后再统一查询这种方法(虽然有点麻烦)。通过存储过程进行分步收集数据后再通过统一查询得出结果,初步逻辑结构如下:
存储过程的处理逻辑基本按照上图所示。这里最重要是利用Job来模拟多线程处理来提高数据获取效率。Job会分别起一个会话来获取数据,执行后数据将会放入一个结果表中。该结果表作为获取数据存储对象按照基础字段建立好索引和分区。最后条件查询结果表将去重后的结果集放入游标返回。
由于用户会进行多次数据获取操作,无可避免结果表中会存在重复的数据出现。这部分重复数据将会在晚上执行另一个Job进行数据清理。
测试代码讲解
这次的存储过程是用package来做,因为整个查询和数据获取的过程都是一个整体,所以放在一起在可读性和完整性都比较好,如下图:
package提供存储过程接口,如下图:
存储过程入口是generate_trajectory方法,dynamic_thread和batch_generate都是嵌套调用的关系,而最后的generate_test_data是用来生成测试数据的,在实际操作上不需要用到。其中package body 的generate_trajectory方法,如下图:
定义了各种变量,最后为job定义了一个动态数组
为传入参数设定一个默认值,由于传入参数中若设定默认值会被传入NULL所替代,所以在这里需要用nvl函数进行预设。在获取数据之前先查询该用户在该时间段是否已经存在数据在结果表中,若存在先进行删除。
根据传入参数thread和配置表中数据进行除法,向下取整后得到一个job中需要执行多少个表的统计,并按照数据进行后续的分页统计。这里调用了dynamic_thread方法,这个方法执行后将返回job编码,获取job编码后放入动态数组中。
由于除法会存在不整除的情况,这部分数据获取将会单独拿出来进行获取,这里直接调用batch_generate方法处理即可。
通过循环去监听全部Job是否已经全部完成,直接统计结果表中去重后的tablename个数,由于每个表的插入语句都是批量插入的,若结果表中存在该表名,则证明该表已经获取完毕(下面会讲到)。
这里对退出循环监听有一些判断,还有的就是超过了5次循环后将会认为超时会强制退出。在这里为了不频繁查询结果,使用了dbms_lock.sleep系统函数做了一下休眠。
退出监听后将会认为是数据获取完毕,这时就需要删除掉刚刚产生出来的job,最后通过查询语句将结果集放入到一个游标中进行返回。
package body 的dynamic_thread方法,如下图:
这个存储过程就是用来生成job用的,job参数是必须要返回的,不然不知道对应的job是那个。
package body 的batch_generate方法,如下图:
定义好各种的变量和游标。
游标SQL用来分页获取配置表中的字段和表名。
通过遍历游标获取到变量信息后进行了一些数据的replace操作是为了使结果表与原始表字段能对应起来。将插入语句写成 insert into… select … from ...的方式进行批量插入当中用到/+APPEND/进行直接路径插入加快插入速度。
至此处理过程结束。
package body 的generate_test_data方法,如下图:
传入参数是rowcounts和gather_person_custom字段,调用这个存储过程的时候可以定义给配置表中定义的每个表批量新增多少条数据,并且这些数据对应的gather_person为那个人。方便数据库层面对数据进行调试。
这里的语句针对目前配置表中数据进行整理,其中包括一些表复合主键的问题处理。
遍历游标获取到表名,时间字段和主键字段。插入前先删除之前上次操作的该人员的数据,并对表名进行修改,后续需要创建临时表,所以这里需要对表名进行修改保证表名在30个字符以内。
这里用了类似java的try...catch...方式创建表。其中create table … as select … from ...在创建临时表时可能会出现表已存在的情况,这时候需要先将已存在的表删除(因为已存在的表中还存在数据,与其删除数据,还不如用drop table … purge方式连表一起删除,这样还可以释放一些表空间),之后再重新新建表。
在使用create table … as select … from ...创建表的时候其实数据也复制了过去了,所以之后添加数据可以通过count方式获取到临时表中记录条数,若新增条数达到用户设定界限则退出循环。若有些表本来就不存在数据的情况下就直接退出循环。
循环插入数据是通过insert into … select … from ...的方式进行插入,由于各个表的字段不同,这里就用*来代替了。
数据插入完成后,先在临时表中进行数据整理,包括更新时间、更新主键和更新gather_person。然后再重新批量插入回原始表中。插入完成后将会把临时表删除释放表空间。
测试结果
v1.0
首先使用了generate_test_data方法为这190+张表每张表插入10w条数据。存储过程第一次获取数据此时结果表为空,启动参数如下:
虽同时启动10个Job执行但结果不太理想,共耗时11138秒,如下图:
这样的结果显然是不能接受的,于是想出了第二套方案。
v1.1
在generate_trajectory方法中屏蔽了删除原来数据的操作,如下图:
由于可以通过晚上从定时器上进行去重工作,这部分的删除工作可以忽略不做来减少时间。
接着在数据插入之前先删除表中的所有索引,如下图:
在启动多个job执行之前先干掉结果表中的所有索引来提高插入速度。
再者,循环启动多线程的时候设定一个休眠时间,如下图:
休眠时间为每个线程生成产生一个时间差,不至于多个线程同时启动抢占资源造成锁表现象出现。
将原来“查询结果表中表的数量是否与配置表中一致”的判断条件去掉,换成用job是否完成来判断,如下图:
结果表中数据量庞大的时候用count来统计表中数量,其实是做了全表扫描性能很差,查询一次要差不多180+秒。于是回归原点来想了一下,反正这里为了都是判断所有的job是否完成这样的话还不如直接找job的信息来判断,于是想到了user_jobs表。当表中this_sec(执行时间)为NULL则表明job已经完成了这时就可以remove掉,若不是就休眠5秒再来判断。
以查询速度来看,这个比之前查询结果表统计的时间少很多而且更能够确切知道job是否已经完成了,完成一个干掉一个。
在删除掉job之后就要重新为结果表添加上索引,如下图:
在最后查询的时候将并行查询打开,如下图:
由于结果表是一个分区表,而且数据量庞大。所以查询开启并行觉得很有必要。
在创建表的时候就将并行开启了。
同理,在batch_generate方法中,在插入部分也将并行开启了,如下图:
维护数据方法data_maintain里面将去重的删除方法改成分批删除,并且通过游标查询找到rowid,直接通过rowid定位进行delete操作,提高删除效率。如下图:
每一个批次10000数据删除。
v1.1测试结果(新增插入)
同样的启动参数,整个获取过程用了1949.778秒。在相同的条件下(结果表为空)v1.1比v1.0中的快了差不多6倍。
v1.1测试结果(存量更新/插入)
在原有数据的基础上再一次执行获取数据,用了2476.376秒。
v1.2
再继续查看服务器允许的最大并行数
修改结果表的并行度改成16
修改存储过程中并行数为14
v1.2测试结果(新增插入)
在结果表为空的情况下获取的结果是1933.32秒,看上去增加并行数并没有减少执行时间。再深入到获取每个方法的执行时间后发现,其实时间都消耗在创建索引的地方去了,因为创建索引是需要内部排序的,三个索引就需要全表扫描三次,这个时间的确是不可忽视。
结论
像这种需要获取大量大表的操作,在关系型数据库中其实不太适合实时获取的,若将这部分数据都放在后台拆分后定时获取效果将会好很多。在使用并行操作后性能瓶颈已不在插入操作,而在重建索引。如果在插入数据前不屏蔽索引又会产生大量索引的redo信息,导致插入慢情况。
经过比较后发现,插入后重建索引效率比直接插入的效率还要高,但是根据demo来看,试验结果还是令人不太满意。目前存储过程在不重建索引的情况下能够将190+表共1800w+条(设定值内)数据在15分钟内插入完成,因此重建索引问题不解决,不推荐使用关系型数据库做类似的获取操作。
相关推荐
- linux安装FTP
-
1、在nkftp目录下安装ftp,进入到nkftp里面[root@localhostbin]#cd/data/nkftp执行安装命令:[root@localhostnkftp]#rpm-i...
- LINUX下搭建FTP服务器
-
FTP服务器介绍FTP是FileTransferProtocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于Internet上的控制文件的双向传输。同时,它也是一个应用程序(App...
- Linux下如何进行FTP设置
-
目录:一、Redhat/CentOS安装vsftp软件二、Ubuntu/Debian安装vsftp软件一、Redhat/CentOS安装vsftp软件1.更新yum源yumupdate-y2.安...
- 推荐使用集串口 SSH远程登录和FTP传输三合一工具MobaXterm
-
来源:百问网作者:韦东山本文字数:1216,阅读时长:4分钟在以前的资料里,串口和SSH远程登使用SecureCRT,window与ubuntu数据传输使用filezilla,窗口切换来切换去,麻烦也...
- 如何搭建FTP服务器(Linux系统)
-
上次说了Windows操作系统下搭建的FTP服务器,那有朋友问我,说买的XX轻量应用服务器都是属于Linux的操作系统,我该如何为搭建FTP服务器呢?...
- Linux 命令 ncftp(文件传输)——想玩转linux就请一直看下去
-
我是IT悟道,点击右上方“关注”,每天分享IT、科技、数码方面的干货。Linuxncftp命令...
- 如何用 ftp 实现一键上传
-
简介ftp是Internet标准文件传输协议的用户界面,它允许用户与远程网络站点之间传输文件...
- Linux安装ftp
-
1安装vsftpd组件安装完后,有/etc/vsftpd/vsftpd.conf文件,是vsftp的配置文件。[root@bogon~]#yum-yinstallvsftpd2添加一个...
- 一天一点点:linux - ftp命令
-
linuxftp命令设置文件系统相关功能。FTP是ARPANet的标准文件传输协议,该网络就是现今Internet的前身。语法ftp[-dignv][主机名称或IP地址]参数:-d详细显示指令执...
- Centos 7 搭建FTP
-
目录安装软件以及启动服务添加防火墙规则关闭selinuxftp配置常用常用参数详解特殊参数配置文件没有的参数也可以添加到配置中1.安装软件以及启动服务yuminstall-yvsftpdsys...
- 【Linux】Linux中ftp命令,没有你想的那么简单
-
本文介绍了Linux中FTP命令的基本用法,包括连接与登录远程服务器,以及解析了FTP协议中五个最常用的操作命令的使用和解析过程。同时,提供了一个包含常用FTP操作命令的表格,供读者参考。通过熟练掌握...
- linux 命令行操作ftp
-
以下是linuxftp命令参数的详解。FTP>!从ftp子系统退出到外壳?FTP>?显示ftp命令说明??和help相同?格式:?[command]说明:[com...
- 多学习才能多赚钱之:linux如何使用ftp
-
linux如何使用ftp步骤1:建立FTP连接想要连接FTP服务器,在命令上中先输入ftp然后空格跟上FTP服务器的域名'domain.com'或者IP地址例如:ftpdom...
- linux常用网络操作方法:ftp命令使用方法
-
常用网络操作方法Linux提供了一组强有力的网络命令来为用户服务,这些工具能够帮助用户登录到远程计算机上、传输文件和执行远程命令等。本节介绍下列几个常用的有关网络操作的命令:ftp传输文件tel...
- Linux 5.15有望合并Memory Folios方案 内核构建速度可提升7%
-
甲骨文公司的长期内核开发人员MatthewWilcox已经研究了“内存对开区”概念相当长的一段时间,这可以改善Linux的内存管理,使其具有更大的效率。例如,使用内存对开的基准测试表明,内核的构建速...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle忘记用户名密码 (59)
- oracle11gr2安装教程 (55)
- mybatis调用oracle存储过程 (67)
- oracle spool的用法 (57)
- oracle asm 磁盘管理 (67)
- 前端 设计模式 (64)
- 前端面试vue (56)
- linux格式化 (55)
- linux图形界面 (62)
- linux文件压缩 (75)
- Linux设置权限 (53)
- linux服务器配置 (62)
- mysql安装linux (71)
- linux启动命令 (59)
- 查看linux磁盘 (72)
- linux用户组 (74)
- linux多线程 (70)
- linux设备驱动 (53)
- linux自启动 (59)
- linux网络命令 (55)
- linux传文件 (60)
- linux打包文件 (58)
- linux查看数据库 (61)
- linux获取ip (64)
- linux进程通信 (63)