REINDEX

REINDEX — перестроить индексы


Синтаксис

RREINDEX [ ( параметр [, ...] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] имя

где параметром может быть:

    CONCURRENTLY [ логическое_значение ]
    TABLESPACE новое_табличное_пространство
    VERBOSE [ логическое_значение ]

Описание

Команда REINDEX перестраивает индекс, используя данные, хранящиеся в таблице индекса, и заменяя его старую копию. Существует несколько сценариев, в которых можно использовать команду REINDEX:

  • Индекс был поврежден и больше не содержит корректных данных. Хотя в теории этого никогда не должно произойти, на практике индексы могут быть повреждены из-за ошибок программного обеспечения или аппаратных сбоев. В таких случаях REINDEX предоставляет метод восстановления.

  • Индекс стал «замусоренным», то есть содержит много пустых или почти пустых страниц. Это может произойти с индексами B-деревьями в QHB при определенных необычных схемах доступа. REINDEX предоставляет способ сократить пространство, занимаемое индексом, записывая новую версию этого индекса без неиспользуемых страниц. Дополнительную информацию см. в разделе Регулярная переиндексация.

  • Вы изменили для индекса параметр хранения (например коэффициент заполнения) и хотите убедиться, что это изменение вступило в силу.

  • Если построение индекса завершается неудачно в режиме CONCURRENTLY, этот индекс остается «нерабочим». Такие индексы бесполезны, но с помощью REINDEX их можно легко перестроить. Обратите внимание, что перестроить нерабочий индекс в неблокирующем режиме способна только команда REINDEX INDEX.


Параметры

INDEX

Пересоздает указанный индекс. Эту форму REINDEX нельзя выполнить в блоке транзакции при использовании с партиционированным индексом.

TABLE

Пересоздает все индексы указанной таблицы. Если таблица имеет дополнительную таблицу «TOAST», то она также будет переиндексирована. Эту форму REINDEX нельзя выполнить в блоке транзакции при использовании с партиционированной таблицей.

SCHEMA

Пересоздает все индексы указанной схемы. Если таблица этой схемы имеет дополнительную таблицу «TOAST», то она тоже будет переиндексирована. Также обрабатываются индексы в разделяемых системных каталогах. Эту форму REINDEX нельзя выполнить внутри блока транзакции.

DATABASE

Пересоздает все индексы в текущей базе данных. Также обрабатываются индексы в разделяемых системных каталогах. Эту форму REINDEX нельзя выполнить внутри блока транзакции.

SYSTEM

Пересоздает все индексы в системных каталогах в текущей базе данных. Сюда входят индексы в разделяемых системных каталогах. Индексы в пользовательских таблицах не обрабатываются. Эту форму REINDEX нельзя выполнить внутри блока транзакции.

имя

Имя конкретного индекса, таблицы или базы данных, подлежащих переиндексации. Имена индексов и таблиц могут быть дополнены схемой. В настоящее время REINDEX DATABASE и REINDEX SYSTEM могут переиндексировать только текущую базу данных, поэтому их параметр должен соответствовать имени текущей базы данных.

CONCURRENTLY

Если используется этот параметр, QHB перестроит индекс, не устанавливая никаких блокировок, которые предотвращают параллельные добавления, изменения или удаления в таблице; тогда как стандартное перестроение индекса блокирует запись (но не чтение) в таблице вплоть до своего завершения. Существует несколько особенностей, которые следует учитывать при использовании этого параметра, — см. параграф Неблокирующее перестроение индексов ниже.

Для временных таблиц REINDEX всегда выполняется в неблокирующем режиме, поскольку никакие другие сеансы не могут к ним обратиться, а этот способ переиндексации менее затратен.

TABLESPACE

Указывает, что индексы будут перестроены в новом табличном пространстве.

VERBOSE

Выводит отчет о ходе выполнения по мере переиндексации каждого индекса.

логическое_значение

Определяет, должен ли выбранный параметр быть включен или выключен. Для включения параметра можно написать TRUE, ON или 1, а для выключения — FALSE, OFF или 0. Кроме того, логическое_значение можно опустить, и в этом случае подразумевается TRUE.

новое_табличное_пространство

Табличное пространство, где будут перестроены индексы.


Примечания

При подозрении на повреждение индекса в пользовательской таблице можно просто перестроить этот индекс или все индексы в этой таблице, используя REINDEX INDEX или REINDEX TABLE.

Все становится сложнее, если нужно восстановить поврежденный индекс в системной таблице. В этом случае важно, чтобы система сама не использовала подозрительные индексы. (В действительности при таком сценарии можно обнаружить, что серверные процессы отказывают сразу в момент запуска вследствие зависимости от поврежденных индексов.) Для безопасного восстановления сервер следует запустить с параметром -P, который не позволяет ему использовать индексы при поиске в системных каталогах.

Один из способов сделать это — выключить сервер и запустить QHB в однопользовательском режиме с параметром -P в командной строке. Затем можно выполнить REINDEX DATABASE, REINDEX SYSTEM, REINDEX TABLE или REINDEX INDEX, в зависимости от того, что вы хотите восстановить. Если сомневаетесь, используйте команду REINDEX SYSTEM, чтобы выбрать восстановление всех системных индексов в базе данных. После этого завершите однопользовательский сеанс сервера и перезапустите сервер в обычном режиме. Дополнительную информацию о том, как взаимодействовать с сервером в однопользовательском интерфейсе, см. в разделе Процесс qhb.

Как вариант, можно запустить обычный сеанс сервера, но добавить в параметры командной строки -P. В разных клиентах метод может различаться, но во всех клиентах на базе libpq можно установить для переменной среды PGOPTIONS значение -P до запуска клиента. Обратите внимание, что хотя этот метод не требует блокировки других клиентов, все же было бы разумно запретить другим пользователям подключаться к поврежденной базе данных до завершения восстановления.

Действие REINDEX подобно удалению и пересозданию индекса в том, что содержимое индекса перестраивается с нуля. Тем не менее блокировки при этом устанавливаются другие. Команда REINDEX блокирует запись, но не чтение из родительской таблицы индекса. Кроме того, она устанавливает на обрабатываемый индекс блокировку ACCESS EXCLUSIVE, которая заблокирует операции чтения, пытающиеся задействовать этот индекс. DROP INDEX, напротив, мгновенно устанавливает блокировку ACCESS EXCLUSIVE на родительской таблице, блокируя как запись, так и чтение. Последующая команда CREATE INDEX блокирует запись, но не чтение; поскольку индекс отсутствует, при чтении не будет попыток обращения к нему, а это значит, что не будет никакой блокировки, но чтение может превратиться в затратное последовательное сканирование.

Для переиндексации одного индекса или таблицы нужно быть владельцем этого индекса или таблицы. Для переиндексации схемы или базы данных нужно быть владельцем этой схемы или базы данных. Обратите внимание, что из-за этого в ряде случаев обычные пользователи могут перестраивать индексы таблиц, принадлежащих другим пользователям. Однако из этих правил есть исключение: когда команду REINDEX DATABASE, REINDEX SCHEMA или REINDEX SYSTEM выполняет обычный пользователь, индексы разделяемых каталогов будут пропущены, если только этот пользователь не владеет данным каталогом (как правило, это не так). Конечно, суперпользователи всегда могут переиндексировать все что угодно.

Переиндексация партиционированных таблиц или партиционированных индексов поддерживается командами REINDEX INDEX или REINDEX TABLE соответственно. Каждая партиция в заданном партиционированном отношении переиндексируется в отдельной транзакции. При работе с партиционированными таблицей или индексом эти команды нельзя выполнять внутри блока транзакции.

При использовании предложения TABLESPACE с REINDEX для партиционированных индекса или таблицы ссылки на табличное пространство изменяются только в листовых партициях. Поскольку партиционированные индексы не изменяются, для них рекомендуется отдельно выполнить ALTER TABLE ONLY, чтобы все присоединяемые новые партиции наследовали новое табличное пространство. При сбое эта команда может не перенести все индексы в новое табличное пространство. Повторный запуск этой команды перестроит все листовые партиции и переместит ранее необработанные индексы в новое табличное пространство.

Если с предложением TABLESPACE указывается SCHEMA, DATABASE или SYSTEM, системные отношения пропускаются, и будет сгенерировано единственное предупреждение (WARNING) об этом. Индексы по таблицам TOAST перестраиваются, но не перемещаются в новое табличное пространство.


Неблокирующее перестроение индексов

Перестроение индекса может помешать обычной работе базы данных. Обычно QHB блокирует от записи таблицу, индекс которой перестраивается, и выполняет всю операцию перестройки индекса за одно сканирование этой таблицы. Другие транзакции по-прежнему могут читать эту таблицу, но при попытке добавления, изменения или удаления строк в ней они будут блокироваться до завершения перестройки индекса. Это может иметь серьезные последствия, если система является действующей производственной базой данных. Индексирование очень больших таблиц может занять много часов, и даже у таблиц меньшего размера перестройка индекса может заблокировать запись в таблицы на неприемлемо долгий для производственной системы срок.

QHB поддерживает перестройку индексов с минимальной блокировкой записи. Этот метод вызывается указанием параметра CONCURRENTLY команды REINDEX. При использовании этого параметра QHB должна выполнить два сканирования таблицы для каждого индекса, который необходимо перестроить, и дождаться завершения всех существующих транзакций, которые потенциально могут использовать этот индекс. В целом, данный метод требует большего количества действий, чем стандартное перестроение индекса, и весь процесс занимает значительно больше времени, поскольку нужно дождаться незавершенных транзакций, которые могут изменить индекс. Однако поскольку этот метод позволяет продолжить обычные операции во время перестройки индекса, он полезен для перестроения индексов в производственной среде. Разумеется, дополнительная загрузка процессора, памяти и ввода/вывода, вызванная перестроением индекса, может замедлить другие операции.

При неблокирующей переиндексации выполняются следующие шаги. Каждый шаг выполняется в отдельной транзакции. Если необходимо перестроить несколько индексов, то каждый шаг по очереди выполняется для всех индексов, и только потом начинается следующий шаг.

  1. В каталог pg_index добавляется новое определение временного индекса. Это определение будет использоваться взамен старого индекса. Чтобы предотвратить любые изменения в схеме во время обработки, на уровне сеанса выполняется блокировка SHARE UPDATE EXCLUSIVE переиндексируемых индексов, а также связанных с ними таблиц.

  2. Первый проход по построению индекса выполняется для каждого нового индекса. После построения индекса его флаг pg_index.indisready переключается в «true», чтобы этот индекс был готов к добавлениям, тем самым делая его видимым для других сеансов сразу после окончания построившей его транзакции. Этот шаг выполняется в отдельной транзакции для каждого индекса.

  3. Затем выполняется второй проход для внесения в индекс кортежей, которые были добавлены во время выполнения первого прохода. Этот шаг также выполняется в отдельной транзакции для каждого индекса.

  4. Все ограничения, ссылающиеся на этот индекс, меняются и начинают ссылаться на определение нового индекса; кроме того, изменяются имена индексов. В этот момент флаг pg_index.indisvalid переключается в «true» для нового индекса и в «false» для старого, и производится сброс кэша, в результате чего все сеансы, которые ссылались на старый индекс, становятся нерабочими.

  5. Для старых индексов флаг pg_index.indisready переключается в «false», чтобы предотвратить добавления новых кортежей, как только завершатся текущие запросы, которые могут ссылаться на старый индекс.

  6. Старые индексы удаляются. Блокировки SHARE UPDATE EXCLUSIVE уровня сеанса, установленные для индексов и таблиц, снимаются.

Если при перестроении индексов возникает проблема, например нарушение уникальности в уникальном индексе, команда REINDEX завершится ошибкой, но оставит после себя «нерабочий» новый индекс в дополнение к уже существующему. Этот индекс будет игнорироваться запросами, поскольку может быть неполным; однако он все равно будет обновляться при изменении данных, что повлечет дополнительные издержки. Команда psql \d сообщит о таком индексе как об INVALID (нерабочем):

qhb=# \d tab
       Table "public.tab"
 Column |  Type   | Modifiers
--------+---------+-----------
 col    | integer |
Indexes:
    "idx" btree (col)
    "idx_ccnew" btree (col) INVALID

Если индекс, отмеченный как INVALID, имеет имя с суффиксом ccnew, то он соответствует временному индексу, созданному во время совмещенной операции, и рекомендуемый метод восстановления состоит в удалении такого индекса командой DROP INDEX и повторной попытке выполнить REINDEX CONCURRENTLY. Если нерабочий индекс имеет суффикс ccold, то он соответствует исходному индексу, который удалить нельзя; рекомендуемый метод восстановления состоит в простом удалении нерабочего индекса, раз уж перестроение индекса прошло успешно.

Обычные построения индексов позволяют одновременно выполняться другим построениям индексов в той же таблице, но неблокирующее построение индексов в таблице может выполняться только одно за раз. В обоих случаях никакие другие изменения схемы таблицы в это время не разрешаются. Другое отличие состоит в том, что обычные команды REINDEX TABLE или REINDEX INDEX могут выполняться в блоке транзакции, а REINDEX CONCURRENTLY — нет.

Как и любая длительная транзакция, REINDEX для таблицы может влиять на то, какие кортежи может удалять параллельная команда VACUUM в любой другой таблице.

REINDEX SYSTEM не поддерживает указание CONCURRENTLY, так как системные каталоги нельзя переиндексировать в неблокирующем режиме.

Более того, индексы, связанные с ограничениями-исключениями, тоже нельзя переиндексировать в неблокирующем режиме. Если явно указать имя такого индекса в этой команде, выдается ошибка. Если таблица или база данных с такими индексами переиндексируются в неблокирующем режиме, эти индексы будут пропущены. (Такие индексы можно переиндексировать без параметра CONCURRENTLY.)

Каждый обслуживающий процесс, запускающий REINDEX, будет записывать ход ее выполнения в представлении pg_stat_progress_create_index. Более подробную информацию см. в подразделе Отчет о ходе выполнения CREATE INDEX.


Примеры

Перестроение одного индекса:

REINDEX INDEX my_index;

Перестроение всех индексов таблицы my_table:

REINDEX TABLE my_table;

Перестроение всех индексов в определенной базе данных исходя из предположения, что целостность системных индексов под сомнением:

$ export PGOPTIONS="-P"
$ psql broken_db
...
broken_db=> REINDEX DATABASE broken_db;
broken_db=> \q

Перестроение индексов таблицы без блокировки одновременных операций чтения и записи в затрагиваемых этим процессом отношениях:

REINDEX TABLE CONCURRENTLY my_broken_table;

Совместимость

В стандарте SQL нет команды REINDEX.


См. также

CREATE INDEX, DROP INDEX, reindexdb, Отчет о ходе выполнения CREATE INDEX