为啥 psycopg2 对我这么慢?
Posted
技术标签:
【中文标题】为啥 psycopg2 对我这么慢?【英文标题】:Why psycopg2 are so slow with me?为什么 psycopg2 对我这么慢? 【发布时间】:2015-01-23 18:16:27 【问题描述】:我有一个使用 psycopg2 与 postgres 一起工作的程序。 但是插入数据库需要太长时间。
这是使用 cProfile 进行分析的结果。
ncalls tottime percall cumtime percall filename:lineno(function)
475 0.022 0.000 855.605 1.801 /home/user/my_project/db.py:197(insert_event)
475 0.012 0.000 293.347 0.618 /home/user/my_project/db.py:123(insert_meta)
475 0.026 0.000 276.814 0.583 /home/user/my_project/db.py:102(insert_image)
2375 0.022 0.000 598.542 0.252 /usr/local/lib/python2.7/dist-packages/psycopg2/extras.py:286(execute)
1425 251.676 0.177 251.676 0.177 method 'commit' of 'psycopg2._psycopg.connection' objects
475 0.005 0.000 33.028 0.070 /home/user/my_project/db.py:83(is_event)
结论:
Insert full information about one event - 1.8 sec
Insert a picture (average) - 0.583 sec
Insert meta data about an event (average) - 0.618 sec
Confirmation of transaction (average) - 0.177 sec
Check availability of a record in DB - 0.070 sec
这是适用于 psycopg2 的代码。
class PostgresDb(object):
def __init__(self, host, port, name, user, password, connect=True):
self.host = host
self.port = port
self.name = name
self.user = user
self.password = password
self.connection = None
self.cursor = None
if connect:
self.connect()
def __str__(self):
return ' '.join(map(str, [self.host,
self.port,
self.name,
self.user]))
def connect(self):
try:
self.connection = psycopg2.connect(host=self.host,
port=self.port,
user=self.user,
password=self.password,
database=self.name)
self.cursor = self.connection.cursor(cursor_factory=psycopg2.extras.NamedTupleCursor)
except psycopg2.DatabaseError as e:
print e
return e.pgerror
def execute(self, query, commit=True, repeat=True):
if self.connection is None:
self.connect()
try:
self.cursor.execute(query)
if commit:
self.connection.commit()
except psycopg2.Error as e:
print e
self.connection = None
return repeat and self.execute(query, commit=commit, repeat=False)
else:
return True
我做错了什么?
也许你知道为什么需要这么长时间。
【问题讨论】:
见***.com/q/12206600/398670。使用COPY
、批次、synchronous_commit = off
...很多不同的选项。
【参考方案1】:
根据您的分析结果,您似乎提交了数千个事务并为每个提交产生了相关的开销(对here 和here 进行了更深入的讨论)。
如果您的要求不一定规定这种细粒度的事务边界,您可能有一个选择是将多个插入批处理到一个事务中,然后对该批处理执行一次commit()
。对于您在此处发布的内容,这可能等同于这种愚蠢的近似值:
db = PostgresDb(...your connection stuff here...)
#
# Other stuff happens, including determining your INSERT queries
#
for query in my_insert_queries[:-1]:
db.execute(query, commit=False)
db.execute(my_insert_queries[-1], commit=True)
我确信有上百万种方法可以切洋葱,具体取决于您的代码的其余部分 - 建议的核心是减少已提交事务的数量。
【讨论】:
【参考方案2】:Psycopg2 对我来说也很慢。 Python 中 CPU 使用率低,Postgres 中 CPU 使用率低,查询耗时较长。不知道是我的数据库连接还是什么,实在是忍无可忍。
试试这个:当您想要进行一堆查询时,请确保它们以分号结尾,然后将它们添加到一个字符串中。实际上不要单独运行它们。最后运行那个巨大的字符串作为查询。如果您需要在事务的中途从数据库中选择内容并在 Python 脚本中使用结果,这将不起作用,但这可能是一种罕见的情况。这极大地加快了我的交易速度。
【讨论】:
以上是关于为啥 psycopg2 对我这么慢?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 psycopg2 查询因 `psycopg2.errors.InternalError_: Assert` 而失败?
为啥 psycopg2 不允许我们在同一个连接中打开多个服务器端游标?
psycopg2.ProgrammingError:语法错误