[英]cx_Oracle: fetchall() stops working with big SELECT statements
我正在尝试从 oracle 数据库中读取数据。 我必须在 python 上阅读返回一百万行的简单选择的结果。
我使用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 rownum < 10000
的 where 条件,python 环境会冻结并且fetchall()
函数永远不会结束。
经过一些试验,我发现了这个精确选择的限制,它可以工作到 50k 行,但如果我选择 60k 行,它就会失败。
是什么导致了这个问题? 我是否必须找到另一种方法来获取这么多数据,或者问题出在 ODBC 连接上? 我怎样才能测试它?
考虑使用 Oracle 的ROWNUM
批量运行。 要合并回单个对象,请附加到不断增长的列表中。 下面假设表的总行数为 1 mill。 根据需要调整:
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)
您可能正在运行 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。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.