cx_Oracle:fetchall() 停止使用大 SELECT 语句
cx_Oracle: fetchall() stops working with big SELECT statements
我正在尝试从 oracle 数据库中读取数据。
我必须阅读 python 一个简单 select 的结果 returns 一百万行。
我使用fetchall()
函数,改变游标的数组大小属性。
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()
函数永远不会结束。
经过一些试验,我发现这个精确的限制 select,它可以工作到 50k 行,但是如果我 select 60k 行它就会失败。
是什么导致了这个问题?我是否必须找到另一种方法来获取这么多数据,或者问题出在 ODBC 连接上?我该如何测试?
考虑使用 Oracle 的 ROWNUM
批量 运行。要合并回单个对象,请附加到不断增长的列表中。下面假设 table 的总行数是 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
以获得最佳性能。
已经给出的重复查询和 select 行子集的建议也值得考虑。如果您使用的是 Oracle DB 12,则有一种更新(更简单)的语法,例如 SELECT * FROM mytab ORDER BY id OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY
.
PS cx_Oracle 不使用 ODBC。
我正在尝试从 oracle 数据库中读取数据。 我必须阅读 python 一个简单 select 的结果 returns 一百万行。
我使用fetchall()
函数,改变游标的数组大小属性。
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()
函数永远不会结束。
经过一些试验,我发现这个精确的限制 select,它可以工作到 50k 行,但是如果我 select 60k 行它就会失败。
是什么导致了这个问题?我是否必须找到另一种方法来获取这么多数据,或者问题出在 ODBC 连接上?我该如何测试?
考虑使用 Oracle 的 ROWNUM
批量 运行。要合并回单个对象,请附加到不断增长的列表中。下面假设 table 的总行数是 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
以获得最佳性能。
已经给出的重复查询和 select 行子集的建议也值得考虑。如果您使用的是 Oracle DB 12,则有一种更新(更简单)的语法,例如 SELECT * FROM mytab ORDER BY id OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY
.
PS cx_Oracle 不使用 ODBC。