Как добавить индекс на колонку в большой таблице без длительной блокировки на запись?

Ответ

Для добавления индекса в большую таблицу без блокировки DML-операций (INSERT, UPDATE, DELETE) используются специальные неблокирующие режимы, которые зависят от используемой СУБД.

PostgreSQL

В PostgreSQL для этого используется опция CONCURRENTLY.

CREATE INDEX CONCURRENTLY idx_name ON table_name (column_name);

Ключевые особенности и риски:

  • Отсутствие блокировок: Команда не блокирует операции записи в таблицу, позволяя приложению работать в штатном режиме.
  • Ресурсоемкость: Процесс занимает больше времени и потребляет больше ресурсов CPU и I/O по сравнению со стандартным CREATE INDEX.
  • Риск неудачи: Если построение индекса завершается с ошибкой, он остается в системе как невалидный (invalid). Такой индекс нужно удалить вручную (DROP INDEX CONCURRENTLY idx_name) и запустить команду заново.
  • Транзакции: Эту команду нельзя выполнять внутри блока транзакции (BEGIN...COMMIT).

MySQL (InnoDB)

В MySQL (для движка InnoDB) используется комбинация ALGORITHM=INPLACE и LOCK=NONE.

ALTER TABLE table_name 
ADD INDEX idx_name (column_name), ALGORITHM=INPLACE, LOCK=NONE;

Ключевые особенности:

  • ALGORITHM=INPLACE: Позволяет избежать создания полной копии таблицы, что значительно ускоряет процесс и снижает нагрузку.
  • LOCK=NONE: Разрешает параллельное выполнение DML-операций во время создания индекса.
  • В современных версиях MySQL (5.6+) такое поведение часто является стандартным для ADD INDEX, но явное указание параметров является хорошей практикой для предсказуемости.