require-concurrent-index-deletion

problem#

A normal DROP INDEX acquires an ACCESS EXCLUSIVE lock on the table, blocking other accesses until the index drop can be completed.

solution#

Ensure all index deletions use the CONCURRENTLY option. CONCURRENTLY waits until conflicting transactions have completed.

https://www.postgresql.org/docs/10/sql-dropindex.html

drop index#

Instead of:

-- blocks reads and writes to table
DROP INDEX "app"."email_idx";

Use:

-- allows reads and writes to table while Postgres waits for conflicting transactions to finish
DROP INDEX CONCURRENTLY "app"."email_idx";

solution for alembic and sqlalchemy#

Instead of:

# migrations/*.py
from alembic import op
def schema_upgrades():
op.drop_index(
"email_idx",
schema="app",
)
def schema_downgrades():
op.create_index(
"email_idx",
"app_user",
["email"],
schema="app",
unique=False,
)

Use:

# migrations/*.py
from alembic import op
def schema_upgrades():
with op.get_context().autocommit_block():
op.drop_index(
"email_idx",
table_name="app_user",
postgresql_concurrently=True,
)
def schema_downgrades():
with op.get_context().autocommit_block():
op.create_index(
op.f("email_idx"),
"app_user",
["email"],
unique=False,
postgresql_concurrently=True,
)