Search code examples
sqlpostgresqlindexingliquibase

How can I create an index on a huge partitioned table with the least disruption to business


I've got a Postgresql database that needs a new index, but I've got to do the indexing concurrently and without locking for more than a couple of seconds at a time. Complications:

  • The table has 2 billion rows.
  • I'm using liquibase, and transactions are making this very complicated, so I've had to do everything with runInTransaction=false
  • Downtime is not an option, because the index wouldn't be worth the effort.
  • The table is partitioned into 16 partitions.
  • I don't know if I should create the partition indexes first and then attach them all at a time when finished, or just do it one after the other.

So option 1 is basically this:

-- changeset me@company.com:JIRA_ticket runInTransaction:false splitStatements:false
CREATE INDEX index ON ONLY table (columns);
CREATE INDEX CONCURRENTLY index_00 ON table_00 (columns);
ALTER INDEX index ATTACH PARTITION index_00;
CREATE INDEX CONCURRENTLY index_01 ON table_01 (columns);
ALTER INDEX index ATTACH PARTITION index_01;
-- Repeat 14 times

While option 2 is this:

-- changeset me@company.com:JIRA_ticket runInTransaction:false splitStatements:false
CREATE INDEX index ON ONLY table (columns);
CREATE INDEX CONCURRENTLY index_00 ON table_00 (columns);
CREATE INDEX CONCURRENTLY index_01 ON table_01 (columns);
-- repeat 14 times
ALTER INDEX index ATTACH PARTITION index_00;
ALTER INDEX index ATTACH PARTITION index_01;
-- repeat 14 times

So: Which of these two options will lead to the least interruptions to business processes, and is there anything I can do to further eliminate locks/downtime?text

I've tried to simulate the query in a dev environment, but that database has 20x less data, and 1000x less traffic, so the simulation is basically worthless.


Solution

  • The ATTACH PARTITION statement needs an ACCESS EXCLUSIVE lock. Skip this step or wrap all of them in a single transaction to make it as short as possible and only once.