Jupyter Notebook中500万行数据批量取数过慢,求优化方案
高效批量获取Oracle大数据量的优化方案
1. 调大游标数组大小(最直接的优化)
原代码每次fetchall()后循环append,而且cx_Oracle默认游标arraysize只有100,这会导致频繁的网络IO交互,拖慢速度。直接把arraysize设成更大的值(比如10000甚至100000,根据服务器内存情况调整),然后批量拉取数据,能大幅减少网络往返次数。
示例代码:
import cx_Oracle # 建立数据库连接 conn = cx_Oracle.connect("用户名/密码@数据库地址") cursor = conn.cursor() # 调整数组大小,越大单次拉取的数据越多 cursor.arraysize = 10000 sql = """SELECT name_employer FROM my_table WHERE section = 'OTHER'""" data = [] cursor.execute(sql) # 循环批量拉取直到没有数据 while True: batch_rows = cursor.fetchmany() if not batch_rows: break data.extend(batch_rows) cursor.close() conn.close()
2. 换掉ROWNUM分页,避免重复扫表
原代码用ROWNUM嵌套分页的方式,每次查询都要重新扫描整个表中符合section='OTHER'的数据,500万行的话重复扫表的开销极大。可以改用基于主键/唯一有序列的分页,比如表有主键id的话,每次只拉取上次批次之后的数据,彻底避免重复扫表:
示例代码(假设表有主键id):
import cx_Oracle conn = cx_Oracle.connect("用户名/密码@数据库地址") cursor = conn.cursor() cursor.arraysize = 10000 batch_size = 10000 last_id = 0 data = [] while True: sql = """SELECT name_employer, id FROM my_table WHERE section = 'OTHER' AND id > :last_id ORDER BY id FETCH FIRST :batch_size ROWS ONLY""" cursor.execute(sql, {'last_id': last_id, 'batch_size': batch_size}) batch_rows = cursor.fetchall() if not batch_rows: break data.extend(batch_rows) # 更新last_id为当前批次最后一条数据的id last_id = batch_rows[-1][1] cursor.close() conn.close()
3. 用更底层的批量API减少内存开销
如果数据量实在太大,还可以结合numpy直接把数据读取到数组里,减少Python对象创建的开销,速度会更快:
示例代码:
import cx_Oracle import numpy as np conn = cx_Oracle.connect("用户名/密码@数据库地址") cursor = conn.cursor() cursor.arraysize = 100000 sql = """SELECT name_employer FROM my_table WHERE section = 'OTHER'""" cursor.execute(sql) # 根据字段类型调整dtype,比如这里假设name_employer是字符串类型 data = cursor.fetchall_array(np.dtype("U100")) cursor.close() conn.close()
额外优化建议
- 确保
section字段有索引,这样数据库过滤数据的速度会快很多 - 如果不需要把所有数据都存在内存里,直接边读边处理(比如写入CSV、写入其他数据库),避免内存不足拖慢速度
- 只查询需要的字段,别用
SELECT *(你原代码已经做到了,继续保持)
内容的提问来源于stack exchange,提问作者Sang Nguyen
相关产品推荐
相关产品推荐

