Python ETL—使用cx_Oracle批量或迭代地将大型数据集加载到Oracle数据库中
使用Python将包含10MM记录的数据集加载到Oracle数据库表中。 创建的数据帧没有问题。从cx_或LCE加载数据帧记录计数时出现过大错误 试图在数据帧上循环并通过一次插入100k记录批量加载10MM记录 下面的代码shwon可以工作,但只适用于适合分配内存的小数据集。我需要一个适用于批量和大型数据集的 已经尝试在行上迭代,但这需要很长时间。我们也尝试过加载更小的数据帧——这是可行的,但没有达到目的 还尝试使用Bindarray和数组大小来lad数据帧,但没有任何效果Python ETL—使用cx_Oracle批量或迭代地将大型数据集加载到Oracle数据库中,python,oracle,dataframe,plsql,cx-oracle,Python,Oracle,Dataframe,Plsql,Cx Oracle,使用Python将包含10MM记录的数据集加载到Oracle数据库表中。 创建的数据帧没有问题。从cx_或LCE加载数据帧记录计数时出现过大错误 试图在数据帧上循环并通过一次插入100k记录批量加载10MM记录 下面的代码shwon可以工作,但只适用于适合分配内存的小数据集。我需要一个适用于批量和大型数据集的 已经尝试在行上迭代,但这需要很长时间。我们也尝试过加载更小的数据帧——这是可行的,但没有达到目的 还尝试使用Bindarray和数组大小来lad数据帧,但没有任何效果 import pan
import pandas as pd
import datetime
import sys
import re
from itertools import groupby, islice, takewhile
import cx_Oracle
format = '%y_%m_%d'
TODAY = datetime.date.today()
add = datetime.timedelta(days=1)
yesterday = datetime.date.today() - add
dd = datetime.date.strftime(TODAY,format)
# connection variables
connection = cx_Oracle.connect("user/Oracle_database_connect_info")
cur = connection.cursor()
# dataframe headers
columns = ['C1','C2','C3','C4']
# -- >> test and sample the file
csv_df = pd.read_csv(r'csvfile_location')
# add record_id for values
csv_df_idx = csv_df.index.values +1
csv_df.insert(0,column = 'RECORD_ID' , value=csv_df_idx)
### TABLE ALREADY CREATED IN DATABASE ###
for index, row in csv_df.iterrows():
### Insert and Iterate to inset records
### Convert to list for easy load into DB
csv_df_dataset_lst = csv_df.values.tolist()
insert_statement = """
INSERT INTO TEST_LOAD
( RECORD_ID ,C1 ,C2 ,C3 ,C4)values (:1,:2,:3,:4,:5) """
# control number of records to bind for insert
# cur.bindarraysize = 100000 # --->>> did not work
# cur.arraysize = 100000 # --->>> did not work
cur.executemany(insert_statement,csv_df_dataset_lst)
connection.commit()
connection.close()
我明白了。诀窍是编写一个函数,根据要加载的批的大小将数据帧分块 下面是最终代码
import pandas as pd
import numpy as np
import datetime
import sys
import re
from itertools import groupby, islice, takewhile
import cx_Oracle
format = '%y_%m_%d'
TODAY = datetime.date.today()
add = datetime.timedelta(days=1)
yesterday = datetime.date.today() - add
dd = datetime.date.strftime(TODAY,format)
# connection variables
connection = cx_Oracle.connect("user/Oracle_database_connect_info")
cur = connection.cursor()
# dataframe headers
columns = ['C1','C2','C3','C4']
# -- >> test and sample the file
csv_df = pd.read_csv(r'csvfile_location')
# add record_id for values
csv_df_idx = csv_df.index.values +1
csv_df.insert(0,column = 'RECORD_ID' , value=csv_df_idx)
### TABLE ALREADY CREATED IN DATABASE ###
# set batch size ie record count
batch_size = 100000
# create chunker function to separate the dataframe into batches
# Note: last batch will contain smallest amout of records.
def chunker(seq,size):
return(seq[pos:pos+size] for pos in range(0,len(seq),size))
insert_statement = """
INSERT INTO TEST_LOAD
( RECORD_ID ,C1 ,C2 ,C3 ,C4)values (:1,:2,:3,:4,:5) """
# Optional use cursor.prepare so Oracle DB avoids compiling the insert statement over and over
try:
cur.prepare(insert_statement)
except cx_Oracle.DatabaseError as Exception:
printf('Failed to prepare insert cursor')
printException(Exception)
exit(1)
for i in chunker(csv_df,batch_size):
### Insert and Iterate to inset records
### Convert to list for easy load into DB
csv_df_dataset_lst = csv_df.values.tolist()
cur.executemany(insert_statement,csv_df_dataset_lst)
connection.commit()
# record counter to monitor the loading.
number_of_records_loaded = cur.execute("""SELECT COUNT(*), SYSDATE FROM TEST_LOAD GROUP BY SYSDATE""")
record_out = cur.fetchall()
for row in record_out:
print(row)
connection.close()
使用Cursor.prepare()和Cursor.executemany()。您能分享一下在为大型数据集执行此代码时收到的错误消息吗?cx_Oracle.DatabaseError:DPI-1015:数组大小10000000太大了。我想明白了。在python中生成一个函数来分块数据帧,然后在该分块上迭代。由于cx_Oracle使用语句缓存,使用explict cursor.prepare可能没有多大帮助。运行查询来计算记录只会增加开销-为什么需要它?为什么不使用executemany()的batchErrors模式?如果您知道数据大小,可以通过预定义内存来提高效率。您可能想看一下cx_Oracle文档—并不是说有任何一种“正确”的方法可以做到这一点。