Oracle千万级数据入库

摘要:
Oracle 1000万级数据仓库最近编写了一个脚本来解析文件数据并将其插入数据库。一开始,它只是cx_ Oracle模块连接到数据库,创建插入SQL语句,然后循环插入它们。sql=“INSERTINTO{}VALUES”.formatcr.executewithThreadPoolExecutoorsexecutor:executor。地图#这里的数据是一个迭代对象,但现实是如此残酷。接下来,我们需要存储一个26GB甚至更大的txt文件。我妈妈,连记事本都装不下。还有一个问题。这个文件包含大约8000万条数据。插入到表中的数据量太大,这不利于后续操作。

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、批量数据入库

免责声明:文章转载自《Oracle千万级数据入库》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WPF使用Winform PDFView控件用php随机生成福彩双色球号码的2种方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

如何控制多线程执行顺序

现象 public class Test02 { static Thread thread1 = new Thread(new Runnable() { @Override public void run() { System.out.println("thread1");...

多线程之线程同步

Pulse(lockObj)表示释放当前被lock的lockObj,容许其它线程调用。(相当于临时挂起当前线程) Wait(lockObj)表示等待当前被其它线程占用的lockObj。 以下的代码将会交替运行两个线程: class TickTock { object lockOn = new object();...

godror基于ODPI-C的 oracle golang 驱动使用

godror 是一个很不错的oracle golang 驱动,基于ODPI-C 编写,好处是我们需要需要依赖编译 我们只需要安装oracle client 就可以了,不像go-oci8需要编译,同时目前也有一个纯golang 的 oracle驱动,但是目前还不是很稳定,以下是godror的参考使用 参考代码 package main ​ import (...

C#跨线程修改控件——从MSIL和汇编看Invoke, 多线程, 事件与事件委托

相信大家刚开始写winform的时候都遇到过这样的问题,当跨线程修改控件属性时会遇到如下的异常: 线程间操作无效: 从不是创建控件"progressBar1"的线程访问它。 这是相应的产生上述异常的代码: 1 #region Auto-Generated Properties 2 3 // DelegateDemo - Director.cs...

oracle 内置函数(二)字符函数

主要函数: 大小写转换函数 获取子字符串函数(字符串截取) 获取字符串长度函数 字符串连接函数 去除子字符串函数 字符替换函数 字符串出现次数 字符串按照特定符号拆分多行 一、大小写转换 1、upper:转大写 2、lower:转小写  3、initcap:首字母大写 二、获取子字符串函数(字符串截取) substr(str,beginIndex,...

详解Session分布式共享(.NET CORE版)

一、前言&回顾        在上篇文章Session分布式共享 = Session + Redis + Nginx中,好多同学留言问了我好多问题,其中印象深刻的有:nginx挂了怎么办?采用Redis的Session方案与微软Session方案相比,有什么优势呢?Cookie也可以取代Session的,采用Redis的Session方案优势在哪...