Every ALTER TABLE takes an ACCESS EXCLUSIVE lock.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # ====================================================================== # Q: Which schema changes are dangerous on a large table, and how do you perform # them safely? # # Every ALTER TABLE takes an ACCESS EXCLUSIVE lock. If it waits behind a slow # query, it blocks all the queries that follow. Rules: # - Always SET lock_timeout = '5s' in the migration, so it fails fast instead of # "freezing" the site. Then retry. # - ADD COLUMN with a constant default is fast since PostgreSQL 11 (it does not # rewrite the table). # - Index: AddIndexConcurrently with atomic = False. # - NOT NULL or FK on an existing table: first a NOT VALID constraint # (AddConstraintNotValid), then ValidateConstraint in a separate migration, # which does not block writes. # - Column type change or rename: expand/contract (new column, dual write, # backfill, switch, drop). # - Backfill in batches of 1,000-10,000 rows, with a short pause, never a single # UPDATE over the whole table. # - Check the SQL before deploying with manage.py sqlmigrate. A CI tool: django- # migration-linter. # ====================================================================== from django.contrib.postgres.operations import AddIndexConcurrently class Migration(migrations.Migration): atomic = False operations = [ migrations.RunSQL("SET lock_timeout = '5s'", migrations.RunSQL.noop), AddIndexConcurrently('order', models.Index( fields=['company', '-created_at'], name='order_company_created')), ] |