pg中Building Indexes Concurrently

create index的语法中,看到一个关键字concurrently。以下是对concurrently的解释:

当使用这个选项时,PostgreSQL在构建索引时不加任何阻止对表的并发插入、更新或删除的锁;而标准的索引构建会锁定表上的写操作(而不是读操作),直到完成。

在使用此选项时,有几个注意事项—请参阅building indexes concurrently。(这句话很关键,自己当初看的时候并没有特别留意!)

对于临时表,CREATE INDEX始终是非并发的,因为其他会话不能访问它们,而且非并发索引创建代价更低。

  

看完上面的解释的时候,感觉这个功能很好用。直到遇到对一张表执行create index concurrently ... 被另外的表操作阻塞的时候,才感觉这个功能有点鸡肋。

类似下面的场景,在对表b执行concurrently创建索引的时候,会话3被会话2阻塞了。

Sessio1:
Begin;
Lock table a;
Session2:
Begin;
Insert into a values(xxx);
Session3:
Create index concurrently b_idx on b(t);

继续翻看文档Building Indexes Concurrently

创建索引会影响数据库的常规操作。通常,pg会对要创建索引的表加上锁,防止对表的写操作,并且通过对表的一次扫描完成索引的构建。其他事务可以继续对表执行select操作,但是如果尝试insert、update、或delete操作会被阻塞,直到索引创建完成。这对生产库可能会有很大的影响。对大表创建索引,可能需要几个小时;即使对小表,短时间锁住可能也是生产环境不能接受的。

pg支持创建索引的时候不阻塞写操作。通过在create index的时候指定关键字concurrently来实现完成。使用该选项后,pg必须对表执行两次表扫描,此外它必须等待已经存在的、潜在的可能修改或使用索引的事务结束(这里就是坑的所在,pg并不能准确的判断出哪些已存在事务可能会修改该表。比如上面的session 2,并不会涉及到表b) 。因此这种方式需要完成更多的工作、花费更多的时间,相比标准的索引创建。

并发构建索引,先在一个事务中将索引加入到system catalog中,然后在两个或者更多的事务中对表执行两次扫描。在每次表扫描之前,创建索引的会话必须等待已存在的对表执行修改的事务完成结束。在第二次扫描之后,索引创建必须等待在第二次扫描开始之前已存在数据快照的任意事务结束(注意:这里是任意事务,而不是涉及到该表的事务,这也是坑的所在)。最后,索引才被标记为可用,create index命令结束。即使到这一步,创建的索引可能还不能立即被查询使用;最差的情况是,直到在创建索引前的事务都结束才能被使用。

如果在扫描表的时候,遇到了问题,比如死锁、唯一性冲突,create index会发生失败,但是会遗留下一个无效的索引。这个无效索引不会被查询使用,因为是不完整的;但是它仍然有被更新的开销。\d命令会显示该索引的无效:

postgres=# \d tab
       Table "public.tab"
 Column |  Type   | Collation | Nullable | Default 
--------+---------+-----------+----------+---------
 col    | integer |           |          | 
Indexes:
    "idx" btree (col) INVALID

这种场景,推荐的恢复方法是删除后重新执行create index concurrently。(或者使用reindex重建,不过reindex不支持并发创建索引)

 

另一个注意事项就是,在并发创建唯一性索引时,唯一性约束已经在第二次扫描开始前强制执行了。这就意味着在索引被其他查询使用时可能会报唯一性错误、甚至创建索引失败。如果在第二次扫描时发生失败,无效索引仍然会进行唯一性检查。

并发创建表达式索引和部分索引是可以的。不支持在分区表上执行并发创建索引。你可以在每个分区上单独执行并发索引创建,然后在常规地创建分区索引,这样可以减少对分区表的锁定时间,因为在这种场景下,创建分区索引只是元数据操作。

常规索引创建支持在相同的表上同时创建其他索引,但是同一时刻,在一张表上只能执行一个并发索引创建。另一个不同点是,常规对的create index可以在一个事务块中执行,但是create index concurrently是不行的。

 

具体创建过程,可以阅读这篇文章:并行创建索引探析 - Create Index Concurrently

 

猜你喜欢

转载自www.cnblogs.com/abclife/p/13207499.html