PostgreSQL:共享内存不足?

8
我正在使用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 张表,所以我不明白如何因为表锁用完而出现问题...
3个回答

9
当您创建表时,会对其进行独占锁定,该锁定将持续到事务结束。即使您随后删除它。
因此,如果我开始一个事务并创建一个临时表:
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个锁。

所以我猜答案之一是你需要足够的锁来应对事务中添加/删除所有这些表。或者,你可以尝试在查询之间重用临时表,只需截断它们以删除所有临时数据?


5
您是否创建了同名的多个保存点而没有释放它们?
我按照这些说明,重复执行SAVEPOINT savepoint_name但从未执行任何相应的RELEASE SAVEPOINT savepoint_name语句。 PostgreSQL只是掩盖旧的保存点,从不释放它们。 它一直追踪每个保存点,直到它用完锁定的内存。 我认为我的postgresql内存限制要低得多,我只需要 ~ 10,000个保存点就会达到max_locks_per_transaction

1

嗯,你是在一个事务中运行整个创建+查询吗?这可能会解释问题。仅仅因为它发生在你删除表时并不一定意味着什么,那可能只是它用完了免费锁的时候。

如果你正在创建这个东西然后立即删除它,使用视图可能是临时表的替代方案,并且肯定是我的首选。


1
事务如何转换为游标和提交?我没有执行任何提交,但我在查询中使用了新的游标。 - Claudiu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接