psycopg2 Postgres COPY EXPERT到Pandas read_csv使用内存缓冲区失败,返回ValueError

时间:2016-12-20 18:51:35

标签: python pandas

所以我使用Python 3.5中的psycopg2驱动程序运行以下代码到Pandas 19.x.

 buf = io.StringIO()
 cursor = conn.cursor()
 sql_query = 'COPY ('+ base_sql + ' limit 100) TO STDOUT WITH CSV HEADER'
 cursor.copy_expert(sql_query, buf)
 df = pd.read_csv(buf.getvalue(),engine='c')
 buf.close()

从内存缓冲区读取时, read_csv 会破坏块:

pandas\parser.pyx in pandas.parser.TextReader.__cinit__ (pandas\parser.c:4175)()

pandas\parser.pyx in pandas.parser.TextReader._setup_parser_source (pandas\parser.c:8333)()

C:\Users\....\AppData\Local\Continuum\Anaconda3\lib\genericpath.py in exists(path)
     17     """Test whether a path exists.  Returns False for broken symbolic links"""
     18     try:
---> 19         os.stat(path)
     20     except OSError:
     21         return False

ValueError: stat: path too long for Windows

呃......路径? buf在记忆中。我在这里错过了什么?

仅供参考,Copy to似乎按预期工作。

以下解决方案代码

感谢下面的答案,我的查询速度使用此方法加倍,我的内存使用率下降了500%。这是我的最终测试代码,以帮助其他人解决他们的性能问题。我很想看到任何可以改善这一点的代码!请务必在问题中链接回这个问题。

# COPY TO CSV quick and dirty performance test
import io
import sys

start = time.time()
conn_str_copy= r'postgresql+psycopg2://' + user_id + r":" + pswd + r"@xxx.xxx.xxx.xxx:ppppp/my_database"
result = urlparse(conn_str_copy)
username = result.username
password = result.password
database = result.path[1:]
hostname = result.hostname

size = 2**30
buf = io.BytesIO()
# buf = io.StringIO()

engine = create_engine(conn_str_copy)
conn_copy= psycopg2.connect(
    database=database, user=username, password=password, host=hostname)

cursor_copy = conn_copy.cursor()
sql_query = 'COPY ('+ my_sql_query + ' ) TO STDOUT WITH CSV HEADER'
cursor_copy.copy_expert(sql_query,  buf, size)
print('time:', (time.time() - start)/60, 'minutes or ', time.time() - start, 'seconds')
tmp = buf.seek(0)
df = pd.read_csv(buf,engine='c', low_memory=False )
buf.close()
print('time:', (time.time() - start)/60, 'minutes or ', time.time() - start, 'seconds') 

从postgres复制数据的速度约为4分钟,而将其加载到pandas数据帧的时间不到30秒。请注意,复制命令是psycopg2驱动程序的一项功能,可能无法在其他驱动程序中使用。

1 个答案:

答案 0 :(得分:2)

您必须将文件句柄或文件名传递给pandas.read_csv()

传递buf.getvalue()会让大熊猫read_csv相信您传递了文件名,因为对象没有read方法,除了"文件名&# 34;是缓冲区,它看起来太长(窗口限制为文件名255个字符)

你几乎得到了它。由于buf已经是类文件对象,因此只需按原样传递即可。小细节:您必须回放它,因为之前的cursor.copy_expert(sql_query, buf)调用可能使用了write并且buf位置在最后(尝试没有它,您可能会得到一个空的数据帧)

buf.seek(0)  # rewind because you're at the end of the buffer
df = pd.read_csv(buf,engine='c')