2013-10-11 752 views
4

经过大量的谷歌搜索,我想我会问这个问题。我有一段代码,执行以下操作对一个Postgres(9.2)数据库:Postgres交易似乎无缘无故AccessExclusiveLock

  1. 开始交易
  2. 删除索引(5个指标)在桌子上
  3. 插入一百万行到表
  4. 重新创建索引
  5. 提交事务。

我的Postgres阅读告诉我,我应该能够做到这一点,仍然允许其他用户从表中选择(实际上即使使用现有的指标,因为他们还没有降到他们的),而这个操作正在进行中。

我实际上发现的是,表上的所有其他查询(它们是所有 select查询)都卡住了。在查看pg_locks和pg_stat_activity表时,我发现我的事务在表上创建了一个AccessExclusiveLock,以防止其他查询运行。一旦这个事务完成,所有其他查询执行得很好。

所以,我的问题是 - 为什么创建索引/插入数据创建表上的排他锁?不应该使用较少入侵的锁(例如SHARE锁)?

我立足这个在我的官方文档here的阅读 - 所以我没有得到火烧要求从任何人RTFM :)

谢谢
Jalpesh

回答

3

我也想这,但你不能这样做。

它不是创建索引,也不是插入,它正在对表进行AccessExclusive锁定,它是这样做的下降索引。

该文档没有提供获取每种类型锁的每种情况的详尽列表 - 它只提供了说明性示例(但也许应该包括此示例)。

我认为有很多代码部分假定索引不会在表上的AccessShare锁被占用时消失。因此,删除索引需要与索引相冲突。

1

我想你希望能够在批量插入时查询你的表,并通过在插入过程中不保留索引来加速这个批量插入。

我想你可能是能够实现这个使用这个程序:

begin;  

maxid = select max(id) from table_name;  

create index table_name_id_tmp_idx where id<=maxid;  

drop index table_name_id_idx;  

commit;  

begin;  

do_bulk_insert();  

create index table_name_id_idx on table_name(id);  

drop index table_name_id_tmp_idx;  

commit;  

它不会对每一个指标是不可能的,因为你需要这where谓语部分索引,将返回true现有行和false用于插入。但串行列,时间戳等可以工作。

+0

对于'id = X'类型的查询,X硬编码,部分索引不适用于泛型'id =?',或者连接,除非代码也被重写为'其中id =?和id <:maxid'。 –

+0

@Denis:它取决于使用的框架或库。 AFAIK大多数库(PHP PDO,Python psycopg等,但我不确定Java JDBC)不使用Postgres提供的准备好的查询。大多数鼓励使用参数化查询,但在内部替换变量 - Postgres服务器只能看到普通查询,这可以工作。 – Tometzky

+0

最好的我知道,PDO实际上默认为真实准备的语句,除非你明确地请求模拟准备。不知道你提到的其他人,但我倾向于认为Ruby库也使用真实准备的语句。仍然是一个很好的答案,请介意(+1),但有关警告取决于OP或将来用户的使用情况。 –