最近在学习python ,看到了pythod的oracle,不仅可以一次fetch多条,也可以一次insert多条,想写一个复制A表数据到B表的程序来看看实际效率能不能提高。写完发现,非常惊艳!效率提升了近一倍! 当然可能会认为这个没有实际意义,其实不然。

从A表复制数据到B表有很多中方法,一般直接insert即可:

  insert into tableA select * from tableB ;

但是当数据量非常大时,到达上亿水准的时候,这样做就很郁闷了,因为本身会跑很慢,又看不到进度,偶尔还会被数据库因为回滚段不够而悲剧。

所以,这种时候,我一般是用游标来做的:

declare
v_num number ;
begin
v_num:=0 ;
for v_cur in (select t.prod_inst_id , t.acc_num , t.user_name from cust30.prod_inst t where rownum <50000 ) loop
insert into test_prod_inst values (v_cur.prod_inst_id , v_cur.acc_num , v_cur.user_name) ;
v_num:=v_num+1 ;
if mod(v_num,50000) = 0 then
commit ;
end if ;
end loop ;
end ;

  

 (也可以用fetch一次多条的方式:bulk  但是实际测试实际快不了多少)。现在的想法就是拿python替代这个,实际代码如下:

#!/home/orashell/python27/bin/python
# -*- coding: utf-8 -*-
import os
import cx_Oracle #需要设置这个不然插入中文会乱码
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
#目的数据库
trans_to_db = cx_Oracle.connect('user/pass#@servicename')
#来源数据库
trans_from_db = cx_Oracle.connect('user/pass#@servicename')
#打开查询游标
curselect = trans_from_db.cursor()
#打开插入游标
curinsert = trans_to_db.cursor() #根据游标生成插入的语句 需要根据已经打开的游标、目的表名 输出这样的
#insert into test_prod_inst (PROD_INST_ID,ACC_NUM,USER_NAME) values(:1,:2,:3)
#输入 fromcur 为一个已经打开的游标对象
#输入 totable 为目的表名
#输出 returnstr 为生成好的SQL
def getInsertSql( fromcur ,totable ):
#习惯这样做 :) 先生成一个字符串模板 再替换
returnstr = 'insert into '+totable+' (SELECTSTR) values(INSERTSTR)'
# 得到游标的描述 cx_Oracle游标描述 本质为一个元组(见下) 第一列为字段名
#[('PROD_INST_ID', <type 'cx_Oracle.NUMBER'>, 17, None, 16, 0, 0), ('ACC_NUM', <type 'cx_Oracle.STRING'>, 32, 96, None, None, 0), ('USER_NAME', <type 'cx_Oracle.STRING'>, 250, 750, None, None, 1)]
curdesc = fromcur.description
selectstr = ''
insertstr = ''
num=0
#拼好字符串模板的 SELECTSTR 以及 INSERTSTR 部分
for i in curdesc:
num=num+1
selectstr=selectstr+i[0]+','
insertstr=insertstr+':'+str(num)+','
#去掉最后一个','
selectstr=selectstr[0:len(selectstr) - 1]
insertstr=insertstr[0:len(insertstr) - 1]
#替换
returnstr=returnstr.replace('SELECTSTR',selectstr );
returnstr=returnstr.replace('INSERTSTR',insertstr );
return returnstr
#实际执行的函数
def runmain():
#用一个SQL生成游标
curselect.execute('select t.prod_inst_id , t.acc_num , t.user_name from cust30.prod_inst t where rownum<10000 ')
#得到插入游标的
manyinserstr=getInsertSql(curselect, 'test_prod_inst')
#插入游标 prepare
curinsert.prepare(manyinserstr)
while True:
#fetch cx_Oracle fetch 当fetch 一条的时候 得到的是一行数据的元组 但是如果是多行 得到的是一个list
#所以 fetchone的结果不转换 不能使用executemany
x=curselect.fetchmany(5000)
#插入
curinsert.executemany(None, x)
#提交
trans_to_db.commit()
#判断退出
if len(x)==0:
break #执行
if __name__ == '__main__':
runmain()
trans_from_db.close
trans_to_db.close

  

本以为用这个会慢一些,因为实际上,这批数据库是过了网络的(数据-本机-数据库),而使用PLSQL是没有使用网络。但是用这个插了5000万数据,结果却不是这样,用了64秒,而用前文的第一种方式用了113秒,差不多是一倍的效率,这还是一个数据库两个表的复制,如果是两个数据库,跨dblink会更加明显。

原因我猜测是这么两个:

A:在实际insert的时候,cx_Oralce拆成了多个线程去处理。如果考虑实际在特别大数据量的时候,plsql这边也可以分为多个模处理,效率最终可能会卡在IO上。

B:oracle的内存管理更加复杂,会比python这种相当于手动管理的方式,消耗的资源会更多。

期待大神能够解惑。

ORACLE+PYTHON实战:复制A表数据到B表的更多相关文章

  1. MySQL用sql复制表数据到新表的方法

    用sqlyog无法直接复制出一个不同表名的表来,只能copy到其他库上同名的表. 在MySQL数据库中,应该如何用sql将表数据复制到新表中呢? 本人通过试验测试成功了,而且相当简单易懂,速度也非常快 ...

  2. MySQL的奇怪的删表数据文件而表照样能打开

    MySQL的奇怪的删表数据文件而表照样能打开 author:headsen  chen      2017-11-02   17:57:17 现象:删除一个正在运行的mysql数据库的表的数据文件:* ...

  3. mysql复制表数据,多表数据复制到一张表

    对于mysql 复制表数据可以使用 insert into select 方式 示例: $sql="insert into icarzoo.provider(providerId,provi ...

  4. oracle xmltype导入并解析Excel数据 (一)创建表与序

    表说明: T_EXCEL_IMPORT_DATASRC: Excel数据存储表,(使用了xmltype存储Excel数据) 部分字段说明: BUSINESSTYPE: Excel模板类型,一个Exce ...

  5. ABAP 动态备份自建表数据到新表(自建表有数据的情况下要改字段长度或者其他)

    当abaper开发好一个程序给用户使用一段时间后,发现某个字段的长度需要修改,但数据库表中已经存在很多数据,冒然直接改表字段可能会导致数据丢失,这种问题的后果可能非常严重. 所以我想到先复制出一个新表 ...

  6. Excel表数据导入数据库表中

    ***Excel表数据导入到数据库表中 通过数据库表的模板做成‘Excel’表的数据导入到数据库相应的表中(注意:主表 和 从表的关系,要先导‘主表’在导入从表) 过程:通过数据库的导入工具—先导入为 ...

  7. sqlserver数据库导出表结构和表数据生成创建表和insert语句

    问题描述: 有时候我们只需要导出一张表和表数据到另外一个数据库,如果是备份整个库的话,就会很麻烦那样,没法满足需求. 解决方法: 以sqlserver2014为例:把MGActivity数据库的bat ...

  8. hive-hbase-handler方式导入hive表数据到hbase表中

    Hive与HBase的整合功能的实现是利用两者本身对外的API接口互相进行通信,相互通信主要是依靠hive-hbase-handler.jar工具类 : hive-hbase-handler.jar在 ...

  9. sqlserver 清除表数据和拷贝表结构的操作

    最近在做一个ERP系统需要导入数据,因此用到了sql的一些操作,在这里记录一下. 1.清除表数据: Delete from 表名称 where XXX 2.拷贝表结构,需求是新增一个和某个表数据格式一 ...

随机推荐

  1. Cocos 2d-X Lua 游戏添加苹果内购(二) OC和Lua交互代码详解

    这是第二篇 Cocos 2d-X Lua 游戏添加苹果内购(一) 图文详解准备流程 这是前面的第一篇,详细的说明了怎样添加内购项目以及填写银行信息提交以及沙盒测试员的添加使用以及需要我们注意的东西,结 ...

  2. myeclipse+tomcat中出现org.apache.juli.logging.LogFactory这样的错误[转]

      将项目部署好后,启动tomcat后报错,java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory 报这个错说明你用的是t ...

  3. Java基础笔记9

    super关键字 表示父类对象. 1.可以调用父类中被重写的方法. 2.还有调用父类中的构造方法.放在子类构造方法的第一行. 不能和this关键字同时出现. final关键字 1.修饰属性.表示常量. ...

  4. angular核心$watch,$digest,$apply之间的联系

    浏览器事件发生时,会在浏览器的上下文window中执行,而angular有自己的上下文angular content,angular 事件在自己的上下文angular content中执行. $wat ...

  5. 利用python深度学习算法来绘图

    可以画画啊!可以画画啊!可以画画啊! 对,有趣的事情需要讲三遍. 事情是这样的,通过python的深度学习算法包去训练计算机模仿世界名画的风格,然后应用到另一幅画中,不多说直接上图! 这个是世界名画& ...

  6. Javaweb项目开发的前后端解耦的必要性

    JavaWeb项目为何我们要放弃jsp?为何要前后端解耦?为何要动静分离? 使用jsp的痛点: 1.jsp上动态资源和静态资源全部耦合在一起,服务器压力大,因为服务器会收到各种静态资源的http请求, ...

  7. 大话git中的撤销操作

    下面以现实场景作为情境. 基础知识,理解git中的几个区域 本地代码已经add,未commit 修改本地工作目录中的readme.md,添加文字"第一次修改" 然后查看下状态 ➜ ...

  8. ldap数据库--ODSEE--复制协议

    简单介绍一下ODSEE的复制拓扑的建立,复制协议可以通过管理界面进行创建,也可以通过命令行创建.在此之前需要了解一些复制协议的相关概念,这里针对OESEE. 1,复制角色 master(提供者,也可以 ...

  9. java中自动装箱带来的性能问题

    之前没有特别注意自动封装所带来的性能问题,今天看了effective java,实验了一下,结果大吃一惊: 考虑下面这段代码: public static void main(String args[ ...

  10. SQLSERVER实现更改表名,更改列名,更改约束代码

    1.修改表名 格式:sp_rename tablename,newtablename ? 1 sp_rename tablename,newtablename 2.修改字段名 格式:sp_rename ...