我正在尝试从Oracle数据库读取数据。 我必须在python上阅读返回100万行的简单选择的结果。
我使用fetchall()
函数,更改了游标的arraysize属性。
select_qry = db_functions.read_sql_file('src/data/scripts/03_perimetro_select.sql')
dsn_tns = cx_Oracle.makedsn(ip, port, sid)
con = cx_Oracle.connect(user, pwd, dsn_tns)
start = time.time()
cur = con.cursor()
cur.arraysize = 1000
cur.execute('select * from bigtable where rownum < 10000')
res = cur.fetchall()
# print res # uncomment to display the query results
elapsed = (time.time() - start)
print(elapsed, " seconds")
cur.close()
con.close()
如果我删除where条件where rownum < 10000
,则python环境将冻结,并且fetchall()
函数将永远不会结束。
经过一些试验,我发现此精确选择的限制,它可以工作到50k行,但是如果我选择60k行,则失败。
是什么导致此问题?我是否必须找到另一种方式来获取此数量的数据,或者问题是ODBC连接?我该如何测试?
答案 0 :(得分:2)
运行cx_Oracle的计算机上的内存可能已用完。不要使用fetchall()
,因为这将要求cx_Oracle将所有结果保存在内存中。使用类似的方法来获取批记录:
cursor = connection.cursor()
cursor.execute("select employee_id from employees")
res = cursor.fetchmany(numRows=3)
print(res)
res = cursor.fetchmany(numRows=3)
print(res)
在循环中记录fetchmany()
调用,在获取下一组行之前处理应用中的每一批行,并在没有更多数据时退出循环。
无论使用哪种解决方案,请调整cursor.arraysize
以获得最佳性能。
已经给出的重复查询并选择行子集的建议也值得考虑。如果您使用的是Oracle DB 12,则有一种新的(更轻松的)语法,例如SELECT * FROM mytab ORDER BY id OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY
。
PS cx_Oracle不使用ODBC。
答案 1 :(得分:1)
考虑使用Oracle的ROWNUM
批量运行。要合并回单个对象,请追加到不断增加的列表中。下面假设表的总行数为1磨。根据需要进行调整:
table_row_count = 1000000
batch_size = 10000
# PREPARED STATEMENT
sql = """SELECT t.* FROM
(SELECT *, ROWNUM AS row_num
FROM
(SELECT * FROM bigtable ORDER BY primary_id) sub_t
) AS t
WHERE t.row_num BETWEEN :LOWER_BOUND AND :UPPER_BOUND;"""
data = []
for lower_bound in range(0, table_row_count, batch_size):
# BIND PARAMS WITH BOUND LIMITS
cursor.execute(sql, {'LOWER_BOUND': lower_bound,
'UPPER_BOUND': lower_bound + batch_size - 1})
for row in cur.fetchall():
data.append(row)