如何将大型Oracle表的SUBSET加载到Dask数据框中?

时间:2019-08-12 23:34:26

标签: dask

这是我尝试过的:

dask_rf = dd.from_pandas(pd.read_sql('select ...)', conn_cx_Oracle), npartitions = 10)

这给了我一个“大对象”警告,建议使用client.scatter。问题在于,似乎client.scatter首先需要将数据加载到Pandas数据帧中,这就是为什么由于RAM限制我首先使用Dask的原因。

Oracle表太大,无法使用Dask的read_sql_table进行读取,因为read_sql_table不会以任何方式过滤该表。

想法? Dask不适用于我的用例吗?

编辑-以下每个答案以及研究方法之后,这是我尝试转换为使用sqlalchemy表达式的方法:

from sqlalchemy import create_engine, Table, Column, String, MetaData, select

sql_engine = create_engine(f'oracle+cx_oracle://username:password@environment')

metadata = MetaData(bind=sql_engine)

table_reference = Table('table', metadata, autoload=True, schema='schema')

s = select([table_reference ]).where(table_reference .c.field_to_filter == filtered_value)

import dask.dataframe as dd

dask_df = dd.read_sql_table(s, 'sqlalchemy_connection_string', 'index_col', schema = 'schema')

dask_df.count()
  

黄昏系列结构:npartitions = 1 action_timestamp int64   vendor_name ... dtype:int64 Dask名称:dataframe-count-agg,   1996年的任务

dask_df.count().compute()
  

DatabaseError:(cx_Oracle.DatabaseError)ORA-02391:已超出   同时限制SESSIONS_PER_USER(此错误的背景位于:   http://sqlalche.me/e/4xp6

为什么要连接到Oracle?

编辑#2-万一有帮助,我还进行了其他测试。我想证明sqlalchemy可以独立工作,所以我通过以下方式证明了这一点:

result = sql_engine.execute(s)

type(result)
  

sqlalchemy.engine.result.ResultProxy

result.fetchone()
  

显示了结果

这似乎排除了SQLAlchemy / Oracle问题,那么接下来有什么想法可以尝试?

2 个答案:

答案 0 :(得分:1)

  

问题在于,似乎client.scatter需要先将数据加载到Pandas数据框中

那是因为您在这里调用Pandas代码

dd.from_pandas(pd.read_sql('select ...)', conn_cx_Oracle), npartitions = 10)
#              pd.read_sql('select ...)', conn_cx_Oracle) # <<-----

根据read_sql_table docstring 您应该能够传递SQLAlchemy表达式对象。

read_sql_table不接受任意SQL查询字符串的原因是,它需要能够对查询进行分区,因此每个任务仅加载整个任务的一部分。对于许多其他方言,这是一件棘手的事情,因此我们依靠sqlalchemy进行格式化。

答案 1 :(得分:0)

我现在正在寻找相同的东西。

为了不被卡住...您可能没有足够的RAM,但可能有很多可用存储空间。所以...目前的建议

# imports
import pandas as pd 
import cx_Oracle as cx
import dask.dataframe as dd

# Connection stuff
...
conn = ...

# Query
qry = "SELECT * FROM HUGE_TABLE"

# Pandas Chunks
for ix , chunk in enumerate(pd.io.sql.read_sql(qry , conn , ... , chunksize=1000000)):
    pd.DataFrame(chunk).to_csv(f"chunk_{ix}.csv" , sep=";") # or to_parquet 

# Dask dataframe reading from files (chunks)
dataset = dd.read_csv("chunk_*.csv" , sep=";" , blocksie=32e6) # or read_parquet

由于这是IO密集型操作,并且您要执行顺序操作,因此可能需要一段时间。

我建议更快地“导出”是对表进行分区,并按每个分区并行执行块导出。