python - Dataframe 写入 Postgresql 性能不佳

标签 python pandas postgresql dataframe sqlalchemy

在 postgresql 中工作时,我有一个笛卡尔连接生成约 400 万行。 连接耗时约 5 秒,写回数据库耗时约 1 分 45 秒。

数据将需要在 python 中使用,特别是在 pandas 数据框中,因此我正在尝试在 python 中复制相同的数据。我应该在这里说,所有这些测试都在一台机器上运行,所以没有任何东西通过网络。

使用 psycopg2 和 pandas,读取数据并执行连接以获得 400 万行(来自此处的答案:cartesian product in pandas)持续不到 3 秒,令人印象深刻。

然而,将数据写回数据库中的表需要 8 分钟(最佳方法)到 36 分钟以上(加上一些我拒绝的方法,因为我必须在 >1 小时后停止它们)。

虽然我不希望重现“仅 sql”时间,但我希望能够接近 8 分钟(我认为 3-5 分钟不会不合理)。

较慢的方法包括:

36 分钟 - sqlalchemy 的 table.insert(来自此处的“test_sqlalchemy_core”https://docs.sqlalchemy.org/en/latest/faq/performance.html#i-m-inserting-400-000-rows-with-the-orm-and-it-s-really-slow)

13 分钟 - psycopg2.extras.execute_batch (https://stackoverflow.com/a/52124686/3979391)

13-15 分钟(取决于 block 大小)- pandas.dataframe.to_sql(再次使用 sqlalchemy)(https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_sql.html)

最佳方法(~8 分钟)是使用 psycopg2 的 cursor.copy_from 方法(可在此处找到:https://github.com/blaze/odo/issues/614#issuecomment-428332541)。 这涉及首先将数据转储到 csv(通过 io.StringIO 在内存中),仅此一项就需要 2 分钟。

所以,我的问题:

  1. 有人有任何可能更快的方法将数百万行从 pandas 数据帧写入 postgresql 吗?

  2. cursor.copy_from 方法 ( http://initd.org/psycopg/docs/cursor.html ) 的文档声明源对象需要支持 read() 和 readline() 方法(因此需要 io.StringIO)。据推测,如果数据框支持这些方法,我们就可以省去对 csv 的写入。有什么方法可以添加这些方法吗?

谢谢。 吉尔斯

编辑:

在第 2 季度 - pandas 现在可以对 to_sql 和此处给出的示例使用自定义调用:https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#io-sql-method几乎按照我上面的建议进行操作(即它使用 StringIO 直接从 STDIN 复制 csv 数据)。 我发现使用此方法写入速度提高了约 40%,这使 to_sql 接近上述“最佳”方法。

最佳答案

我自己回答问题 1: 看来这个问题更多地与 Postgresql(或者更确切地说是一般的数据库)有关。考虑到本文中提出的要点:https://use-the-index-luke.com/sql/dml/insert我发现了以下内容:

1) 从目标表中删除所有索引导致查询在 9 秒内运行。重建索引(在 postgresql 中)又花费了 12 秒,所以仍然低于其他时间。

2) 在只有一个主键的情况下,插入按主键列排序的行将花费的时间减少到大约三分之一。这是有道理的,因为应该很少或不需要对所需的索引行进行改组。我还验证了这就是为什么我在 postgresql 中的笛卡尔连接首先更快的原因(IE 行按索引排序,纯属偶然),将相同的行放在临时表中(无序)并从中插入实际上花了更长的时间。

3) 我在我们的 mysql 系统上进行了类似的实验,发现在删除索引时插入速度也有同样的提高。然而,对于 mysql,重建索引似乎随时都用完了。

我希望这对通过搜索遇到此问题的其他人有所帮助。

我仍然想知道是否可以在 python 中删除写入 csv 的步骤(上面的问题 2),因为我相信我可以用 python 编写一些比纯 postgresql 更快的东西。

谢谢,贾尔斯

关于python - Dataframe 写入 Postgresql 性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55470614/

相关文章:

postgresql - 如何让 Npgsql 与 EF4 一起工作?

Python:无法导入名称/IndexError:列表索引超出范围

python - 按另一个数据框中的值分组

python - 合并具有不同 left_on 和 right_on 长度列表的两个数据帧

python - 查找数据框所有列的唯一值

Postgresql - 检测变化并调用网络服务

Python 的模拟抛出 AttributeError : 'module' object has no attribute 'patch'

python - 将日期从 xlsb 文件格式化为 MM/DD/YYYY

python - 使用 cv2.drawContours() Python 3 绘制特定轮廓时出现问题

sql - 优化行排除查询