我正在使用Python和psycopg2运行一堆查询。我创建了一个大约200万行的大型临时表,然后使用cur.fetchmany(1000)
从中获取1000行,并运行涉及这些行的更广泛的查询。广泛的查询是自给自足的 - 一旦完成,当我继续下一个1000时,我不再需要他们的结果了。
但是,大约有1000000行,我从psycopg2得到了一个例外:
psycopg2.OperationalError: out of shared memory
HINT: You might need to increase max_locks_per_transaction.
有趣的是,当我执行查询以删除一些更广泛的查询创建的临时表时,就会发生这种情况。
为什么会发生这种情况?有什么办法可以避免吗?令人讨厌的是,这发生在中途,这意味着我必须再次运行它。 max_locks_per_transaction
可能与任何事情有什么关系?
注意:我没有做任何.commit()
,但我正在删除我创建的所有临时表,而且我只是为每次“广泛”交易触摸相同的5个表,所以我不明白桌面锁的耗尽是怎么回事......
答案 0 :(得分:3)
当您创建表时,您将获得一个持续到事务结束的独占锁。即使你然后继续放弃它。
所以如果我开始一个tx并创建一个临时表:
steve@steve@[local] *=# create temp table foo(foo_id int);
CREATE TABLE
steve@steve@[local] *=# select * from pg_locks where pid = pg_backend_pid();
locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | mode | granted
---------------+----------+-----------+------+-------+------------+---------------+---------+-----------+----------+--------------------+-------+---------------------+---------
virtualxid | | | | | 2/105315 | | | | | 2/105315 | 19098 | ExclusiveLock | t
transactionid | | | | | | 291788 | | | | 2/105315 | 19098 | ExclusiveLock | t
relation | 17631 | 10985 | | | | | | | | 2/105315 | 19098 | AccessShareLock | t
relation | 17631 | 214780901 | | | | | | | | 2/105315 | 19098 | AccessExclusiveLock | t
object | 17631 | | | | | | 2615 | 124616403 | 0 | 2/105315 | 19098 | AccessExclusiveLock | t
object | 0 | | | | | | 1260 | 16384 | 0 | 2/105315 | 19098 | AccessShareLock | t
(6 rows)
当我放弃表格时,这些“关系”锁定不会被删除:
steve@steve@[local] *=# drop table foo;
DROP TABLE
steve@steve@[local] *=# select * from pg_locks where pid = pg_backend_pid();
locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | mode | granted
---------------+----------+-----------+------+-------+------------+---------------+---------+-----------+----------+--------------------+-------+---------------------+---------
virtualxid | | | | | 2/105315 | | | | | 2/105315 | 19098 | ExclusiveLock | t
object | 17631 | | | | | | 1247 | 214780902 | 0 | 2/105315 | 19098 | AccessExclusiveLock | t
transactionid | | | | | | 291788 | | | | 2/105315 | 19098 | ExclusiveLock | t
relation | 17631 | 10985 | | | | | | | | 2/105315 | 19098 | AccessShareLock | t
relation | 17631 | 214780901 | | | | | | | | 2/105315 | 19098 | AccessExclusiveLock | t
object | 17631 | | | | | | 2615 | 124616403 | 0 | 2/105315 | 19098 | AccessExclusiveLock | t
object | 17631 | | | | | | 1247 | 214780903 | 0 | 2/105315 | 19098 | AccessExclusiveLock | t
object | 0 | | | | | | 1260 | 16384 | 0 | 2/105315 | 19098 | AccessShareLock | t
(8 rows)
事实上,它又增加了两个锁...似乎我不断创建/删除那个临时表,每次增加3个锁。
所以我猜一个答案是你需要足够的锁来处理在整个事务中添加/删除的所有这些表。或者,您可以尝试在查询之间重用临时表,只需截断它们以删除所有临时数据吗?
答案 1 :(得分:3)
您是否创建了多个具有相同名称的保存点而未释放它们?
我跟着these instructions,反复执行
SAVEPOINT savepoint_name
但没有执行任何相应的RELEASE SAVEPOINT savepoint_name
语句。 PostgreSQL只是掩盖旧的保存点,从不释放它们。它跟踪每个,直到锁内存耗尽。我认为我的postgresql内存限制要低得多,我只花了大约10,000个保存点来点击max_locks_per_transaction。
答案 2 :(得分:1)
那么,您是在单个事务中运行整个create +查询吗?这或许可以解释这个问题。只是因为当你丢桌时它发生并不一定意味着任何事情,这可能恰好是它用完了免费锁的时候。
使用视图可能是临时表的替代方法,如果你正在创建这个东西然后立即删除它,肯定会通过我的第一个选择。