Files
django-migration-linter/tests/fixtures.py
T
David Cain 0c5519d9dc Add new check for indexing with atomic=True
Briefly, this check helps prevent a long-running index creation from
preventing all reads and writes to a table.

This supplements an existing check
==================================
There is an existing check, `CREATE_INDEX` which warns about creating
indices without the `CONCURRENTLY` argument. It's a helpful check!

However, there are some valid reasons to prefer non-concurrent index
creation. For example, concurrent index creation may struggle to
complete when applied to write-heavy tables (since Postgres will have to
make repeated passes on the table to accommodate the new reads since the
last round).

The danger of `EXCLUSIVE` locks
===============================
If you *do* want to create indices nonconcurrently, there is still a
**huge footgun** to be aware of -- locks which are held in a transaction
are not released until the transaction closes.

Dangerous Django defaults
=========================
By default, any time you add a new Django field with `db_index=True` or
`unique=True`, the automatically generated `Migration` has:

- implicit setting of `atomic=True` (transactions are on)
- an `ALTER TABLE...ADD COLUMN` call (exclusively locks the table)
- a `CREATE INDEX` invocation (*hopefully* quick, due to nullable
  columns)

It's even more dangerous if you combine an `ALTER TABLE` call with
`CREATE INDEX` of an existing, non-nullable column.

Favor `atomic=False` if you must index
======================================
Index-creating migrations should have few `operations`. Since index
creation does not modify row-level data (and only requires locking
against writes), there's no reason to use transactions.

It's prudent to bypass the default `atomic=True` for index creation.
2023-07-09 14:42:35 +02:00

19 lines
853 B
Python

from __future__ import annotations
CREATE_TABLE_WITH_NOT_NULL_COLUMN = "app_create_table_with_not_null_column"
ADD_NOT_NULL_COLUMN = "app_add_not_null_column"
DROP_COLUMN = "app_drop_column"
DROP_TABLE = "app_drop_table"
RENAME_COLUMN = "app_rename_column"
RENAME_TABLE = "app_rename_table"
IGNORE_MIGRATION = "app_ignore_migration"
ADD_NOT_NULL_COLUMN_FOLLOWED_BY_DEFAULT = "app_add_not_null_column_followed_by_default"
ALTER_COLUMN = "app_alter_column"
ALTER_COLUMN_DROP_NOT_NULL = "app_alter_column_drop_not_null"
DROP_UNIQUE_TOGETHER = "app_unique_together"
ADD_MANYTOMANY_FIELD = "app_add_manytomany_field"
DATA_MIGRATIONS = "app_data_migrations"
MAKE_NOT_NULL_WITH_DJANGO_DEFAULT = "app_make_not_null_with_django_default"
MAKE_NOT_NULL_WITH_LIB_DEFAULT = "app_make_not_null_with_lib_default"
CREATE_INDEX_EXCLUSIVE = "app_create_index_exclusive"