[PGSQL]PostgreSQL并行创建索引

 

并行创建索引

通常,在创建索引的时候 PostgreSQL 会锁定表以防止写入,然后对表做一次完整扫描以完成索引的创建。在此过程中其他事务仍然可以读取表,但是插入、更新、删除将被一直阻塞到索引创建完毕。这样做对于处于活跃状态的数据库可能会产生严重的性能影响。因为某些很大的表可能需要数个小时的时间来建立索引,而且即使对于生产中正在使用的较小的表,这种阻塞通常也是不可接受的。在oracle数据库中在建索引中可以加“online”,这样不 会出现锁表的情况了。同样在PostgreSQL 允许在 CREATE INDEX 创建索引时使用 CONCURRENTLY 选项指定不锁定表。与oracle中类似, PostgreSQL 就必须对表扫描两次,并且必须等待所有正在执行的事务完成。这种方法增加了总体工作量并且可能需要非常长的时间才能完成索引的创建。然而由于这种方法允许在创建索引的同时进行常规操作,因此这种方法适合于在运行过程中添加新索引。当然,创建索引所需要的额外 CPU 和 I/O 开销仍然会对其它操作有不利影响。

使用CONCURRENTLY 选项需要注意的地方:

  • 如果在对表进行第二次扫描的时候出现了问题,比如在唯一索引字段上出现了重复值,CREATE INDEX 命令将会失败并遗留下一个"非法"的索引。这个"非法"索引将被忽略,因为它可能是不完整的,当然它也不会导致更新、插入、删除时的额外开销。在这种情况下推荐删除该索引然后尝试重新执行 CREATE INDEX CONCURRENTLY 命令,另一种可能的方法是使用 REINDEX 重建索引。由于 REINDEX 不支持并行创建索引,因此可能不是一个好方法。
  • 对于并行创建唯一索引还有一个警告:在开始对表进行第二次扫描的时候,已经在其他事务上强制进行唯一约束了。这意味着在索引创建完毕之前,如果有其它违反唯一约束的行为那么将会报错,甚至在索引最终创建失败的情况下也是如此。同样,如果在第二次扫描的过程中发生错误,生成的"非法"索引仍将在随后强制执行唯一约束的检查。
  • 并行创建表达式索引和部分索引也是可以的。在表达式求值过程中发生的错误同样也会在唯一约束索引上导致类似前面描述过的行为。

在创建普通索引的同时还允许在同一张表上创建其他普通索引,但是在一张表上只能进行一个并行索引的创建。在此两种情况下,都不允许同时对表所在的模式进行修改。另一个差异是 CREATE INDEX 可以放在一个事务块中执行,但 CREATE INDEX CONCURRENTLY 不可以。

在PostgreSQL中有比oracle更强大的地方,可以对相同的列建两个索引,而在oracle中是不行的,所以在PostgreSQL,可以这样做,再建一个一样的索引,然后把旧索引删除。这样,建索引的时候,旧的访问仍然可以使用旧的索引。而在oracle中即使online rebuild索引,并发访问比较大的时候,有时也容易出问题。