ORACLE+PYTHON实战:复制A表数据到B表

最近在学习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这种相当于手动管理的方式,消耗的资源会更多。

期待大神能够解惑。

时间: 2024-08-28 10:42:43

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

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

Hive与HBase的整合功能的实现是利用两者本身对外的API接口互相进行通信,相互通信主要是依靠hive-hbase-handler.jar工具类 : hive-hbase-handler.jar在hive的lib包中而不是在hbase的lib中,hive0.6版本以后: 创建hive表的同时创建hbase表,删除 hive表的同时也会删除对应的hbase表. 参见官方文档:https://cwiki.apache.org/confluence/display/Hive/HBaseIntegr

Excel表数据导入数据库表中

***Excel表数据导入到数据库表中 通过数据库表的模板做成‘Excel’表的数据导入到数据库相应的表中(注意:主表 和 从表的关系,要先导‘主表’在导入从表) 过程:通过数据库的导入工具—先导入为一张临时表,在插入到正式表中.语句如下: --YK_TYPK插入数据 insert into YK_TYPK --插入'YK_TYPK(通用品库)'数据 select * from Sheet1$_TYPK_caoyao ---------------------------------------

Linux下mysql多表数据拆分单表

需求 写代码以前都复制粘贴,菜的一比,第一次碰见一个生活中的实际需求,哎,数据结构和流,线程还是得认真学啊 表结构如下 #!/bin/bash# ** 存储过程名称: ysp.ddl# ** 功能描述: # ** 创建者: wx# ** 创建日期: # ** 修改者: # ** 创建日期: # ** 修改内容: drop table if exists ods_payment_flow_sf7;create table ods_payment_flow_sf7(paymentid        

SQL Server复制表结构和表数据生成新表的语句

参考:http://topic.csdn.net/t/20020621/09/820025.html SELECT   *   INTO   newTableName   FROM   oldTableName 此方法将把旧表的结构和数据同时copy生成新表,不过主键外键约束没有生成,需要手动设置.

查询oracle 数据库中回滚段中一个时间点被修改的表数据并还原表中原来数据

利用下面的SQL就可以查处最近更改的数据. SQL> SELECT ID,NAME,VERSIONS_STARTTIME,VERSIONS_ENDTIME,VERSIONS_OPERATION FROM TEST VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAXVALUE WHERE VERSIONS_STARTTIME IS NOT NULL ORDER BY VERSIONS_STARTTIME DESC; 通过以上小实验可以看出,VERSIONS_ST

Python抓取Excel表数据至MySQL表

#encoding=utf-8 import xlrd import MySQLdb data=xlrd.open_workbook('test.xlsx') table=data.sheets()[0] nrows=table.nrows ncols=table.ncols tabledict={} for i in range(nrows): tabledict[i]=table.row_values(i) print tabledict[2] print tuple(tabledict[2

mysql 存储过程复制A表数据到B表

create procedure sys_message_user_for_busbase() begin -- 声明一个标志done, 用来判断游标是否遍历完成 DECLARE done INT DEFAULT 0; -- 声明一个变量,用来存放从游标中提取的数据 -- 特别注意这里的名字不能与由游标中使用的列明相同,否则得到的数据都是NULL DECLARE tid varchar(50) DEFAULT NULL; DECLARE tname varchar(50) DEFAULT NUL

Oracle中复制表结构和表数据

Oracle中复制表结构和表数据 1. 复制表结构及其数据(目标表不存在): create table table_name_new as select * from table_name_old; 2. 只复制表结构(目标表不存在,加入一个永远不可能成立的条件.): create table table_name_new as select * from table_name_old where 1=2; 3. 只复制表数据(目标表已经存在): 如果两个表结构一样: insert into t

oracle 两表数据对比---minus

    1 引言 在程序设计的过程中,往往会遇到两个记录集的比较.如华东电网PMS接口中实现传递一天中变更(新增.修改.删除)的数据.实现的方式有多种,如编程存储过程返回游标,在存储过程中对两批数据进行比较等等. 本文主要讨论利用ORACLE的MINUS函数,直接实现两个记录集的比较. 2 实现步骤 假设两个记录集分别以表的方式存在,原始表为A,产生的比较表为B. 2.1 判断原始表和比较表的增量差异 利用MINUS函数,判断原始表与比较表的增量差异. 此增量数据包含两部分: 1)原始表A有.比