cx_oracle:fetchall停止使用大型选择指令工作

时间:2018-12-06 14:47:22

标签: python oracle odbc cx-oracle fetchall

我正在尝试从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连接?我该如何测试?

2 个答案:

答案 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)