我尝试了cx_Oracle包fetchall((,但最终消耗了大量RAM,也尝试过熊猫,但在我们有数十亿记录的情况下,这似乎也没有那么有效。
我的用例-从oracle表中提取每一行到python,进行一些处理并将其加载到另一个表中。PS-期待类似fetchmany((的东西,尝试了这个,但没能让它工作。
对于您的大数据集,因为您的机器的内存是"太小";,然后,您将不得不对行集进行批处理,并在获取下一个集之前重新插入每个集。
调整Cursor.arraysize
和Cursor.prefetchrows
(cx_Oracle 8中的新增功能(对获取性能非常重要。该值用于内部缓冲区大小,无论使用fetchone()
还是fetchmany()
。请参阅调整cx_Oracle。
重新插入值时使用executemany()
,请参阅批处理语句执行和大容量加载。
最大的问题是,你是否需要提取到Python中,或者你是否可以在PL/SQL或SQL中进行操作——使用这两种方法将消除跨网络传输数据的需要,因此效率会高得多。
一般来说,您的策略应该如下。
- 编写一个sql查询,获取所需的数据
- 执行查询
- 循环:从结果中读取元组
- 处理元组
- 将处理后的内容写入目标关系
但是有很多细节需要处理。
通常,在执行这次的查询时,您会希望读取数据库的一个版本。如果同时对相同的数据进行写入,则会得到一个过时的版本,但不会阻碍写入程序。如果你想要最新的版本,你有一个很难解决的问题。
执行步骤4时,不要打开新的连接,而是重新使用连接。打开一个新的连接就像发射一艘战舰。
最好是在目标关系上没有任何索引,因为每次编写元组时都要支付更新目标关系的费用。它会起作用,但会慢一些。您可以在完成处理后构建索引。
如果这个实现对你来说太慢了,那么加快速度的一个简单方法就是一次处理1000个元组,然后批量写入。如果速度太慢,那么您已经进入了数据库性能调优的黑暗世界。
您可以使用偏移限制属性。如果数据可以按列(主键或列的组合,以便在整个执行过程中数据的顺序相同(排序,下面是我尝试的。
我计算一下这张表的总数。根据区块大小(例如:100000(,创建一个值列表[0,0+chunk,0+chunk2…count(*(]。
例如:如果count(*(=2222,chunk=100,则输出列表为:[0100200,…2222]
然后使用上面列表的值,我通过使用"偏移I行仅获取下一个j值"来获取每个分区。这将在不重叠任何数据的情况下选择分区中的数据。
我在每次迭代中更改I和j的值,以便获得完整的数据。在运行时,给定的块是100000;那么多数据被加载到内存中。您可以根据系统规范将其更改为任何值。
在每次迭代中,将数据保存到您想要的任何位置。