Oracle千万级数据入库

Oracle千万级数据入库

最近在写一个解析文件数据(txt、json、csv)并插入到数据库中的脚本(基于Python和Oracle)。

刚开始做的时候就是只是用cx_Oracle模块连接数据库,建立insert SQL语句,然后循环给里面插。很简单也很容易就实现了。

后面就遇到了唯一一个问题。就是大数据的解析处理。刚开始我用的是一个50多M的json数据,还有一个3M多的txt文件,这些都成功入库了。紧接着马上就遇到GB级别的json文件和txt文件。人就有点懵了,光怎么解析数据就花了两天时间去研究(json数据格式很严谨,大文件情况先很难直接加载到内存中,最终使用了ijson模块流式解析json文件解决了这个问题,txt文件还好说,可以一行一行的读)。

后面简单测试了一下,45万条的json数据插入用了接近一个小时的时间,这是不可容忍的,只能说代码质量太差。没有考虑到性能的问题。

为了解决插入速度问题,首先想到的是多线程,将多线程用上去之后,几分钟就解决了问题,速度还能接受。到此为止就没有接着往下研究了。这是我第一次修改后的主要代码。就添加了一个多线程,看到插入速度还可以,就没有继续深究了。

sql = "INSERT INTO {}(ID, NAME) VALUES ( {} '{}')" .format(tableName, id, name)
cr.execute(sql)

with ThreadPoolExecutor(30) as executor:
   executor.map(func, data)
   #这里的data是一个可迭代的对象

然而现实就是如此的残酷,接下来要入库一个26GB甚至更大的txt文件,我的妈啊,大到notepad都加载不出来的那种,而且还有一个问题,这个文件大概是8000多万条数据,插到一个表中表的数据量太大,对后续操作也不利。于是想到了将这个文件拆分,我在这里是拆分成了5个小的txt文件,每个txt文件的极限数据量设置为了2000w。接下来就是入库的问题了。在网上查阅了一些资料,对我的代码来说,可以在sql语句上进行优化。

将原来的参数传递改成了绑定变量的时候,原因是sql语句在数据库中解析的时候消耗很多资源,分为硬解析和软解析,有兴趣的可以看一下,我这里只提一下我的优化过程。

sql = "INSERT INTO {}(ID, NAME) VALUES ( :ID, :NAME)" .format(tableName)
data = {"ID":1,
      "NAME":name}
cr.execute(sql, data)

这个我测试了170w的数据量,在使用变量传参的情况下,插入170w数据花费了280s左右的时间,使用绑定的方式后变成了220s左右,大概省了一分钟,但是这还是达不到要求的,这样的速度对于将近亿级别的数据量来说还是太low了。接下来怎么优化呢,多线程也使用过了,绑定变量也用过了,速度还是不太行,在网上再次查询看到了批量插入的方式(其实这个很早就查到了,但是对我的数据来说,改造成这样太麻烦也就没有去使用),没办法了只能尝试下这种优化方式了。

具体不再细说,直接上部分代码吧。

sql = "INSERT INTO {}(ID, NAME) VALUES ( :ID, :NAME)" .format(tableName)
data = [(1, '小红'), (2, '小明')]
cr.executemany(sql, data)

这里的data是一个列表,列表元素是元组,一个元组对应一条数据。

最后这个批量插入数据大大优化了插入速度,8000w数据大概十几分钟插完。很棒!

里面很多细节都没有展开提到,因为我也不懂,就知道是这么用的。

这个就记录下我的目前的三次优化过程吧。

1、多线程

2、绑定变量

3、批量数据入库

posted @ 2020-06-12 20:45  超级宇宙无敌乖宝宝  阅读(1941)  评论(0编辑  收藏  举报