在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分钟(取决于块大小)-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的写入。有什么方法可以添加这些方法吗?
谢谢。 吉尔斯
答案 0 :(得分:0)
回答自己的问题1: 看来这个问题与Postgresql(或更确切地说是数据库)有更多关系。考虑到本文中提出的要点:https://use-the-index-luke.com/sql/dml/insert我发现了以下内容:
1)从目标表中删除所有索引导致查询在9秒钟内运行。 (在postgresql中)重建索引又花了12秒钟,所以在其他时候还是很好。
2)仅在有主键的情况下,插入按主键列排序的行可将花费的时间减少到大约三分之一。这是有道理的,因为所需的索引行应该很少或没有改组。我还验证了这就是为什么我在笛卡尔中进行笛卡尔连接首先要快一些的原因(即行是由索引排序的,纯粹是偶然的缘故),将相同的行放在临时表中(无序)并从中插入实际上花了更长的时间。
3)我在我们的mysql系统上尝试了类似的实验,发现删除索引时插入速度有所提高。但是,使用mysql似乎可以重建索引,只要花费任何时间就可以用完。
我希望这可以帮助其他在搜索中遇到此问题的人。
我仍然想知道是否有可能在python中删除对csv的写入步骤(上述第二季度),因为我相信我可以在python中编写比纯postgresql更快的东西。
谢谢,吉尔斯