REINDEX#

REINDEX

REINDEX

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

Синтаксис

REINDEX [ ( option [, ...] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] name

where option can be one of:

    CONCURRENTLY [ boolean ]
    TABLESPACE new_tablespace
    VERBOSE [ boolean ]

Описание

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

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

  • Индекс стал раздутым, то есть он содержит много пустых или почти пустых страниц. Это может произойти с индексами B-дерева в Tantor SE при определенных нестандартных сценариях доступа. REINDEX предоставляет способ уменьшить потребление пространства индексом путем записи новой версии индекса без мертвых страниц. См. Раздел 24.2 для получения дополнительной информации.

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

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

Параметры

INDEX

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

TABLE

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

SCHEMA

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

DATABASE

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

SYSTEM

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

name

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

CONCURRENTLY

Когда используется эта опция, Tantor SE будет перестраивать индекс без блокировки, которая препятствует одновременным вставкам, обновлениям или удалениям в таблице; в то время как стандартная перестройка индекса блокирует записи (но не чтение) в таблице до ее завершения. Существует несколько оговорок, о которых следует знать при использовании этой опции — см. Rebuilding Indexes Concurrently ниже.

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

TABLESPACE

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

VERBOSE

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

boolean

Определяет, должна ли быть включена или выключена выбранная опция. Вы можете написать TRUE, ON или 1, чтобы включить опцию, и FALSE, OFF или 0, чтобы отключить ее. Значение boolean также можно опустить, в этом случае предполагается TRUE.

new_tablespace

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

Примечания

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

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

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

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

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

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

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

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

Если используется SCHEMA, DATABASE или SYSTEM с TABLESPACE, системные отношения будут прне указаны и будет сгенерировано одно WARNING. Индексы на TOAST-таблицах будут перестроены, но не перемещены в новое табличнoe пространствo.

Перестроение индексов одновременно

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

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

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

  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:

postgres=# \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. Подробности см. в разделе Раздел 27.4.2.

Примеры

Перестроить один индекс:

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.