REINDEX

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

Синтаксис

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

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

    VERBOSE

Описание

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

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

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

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

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

Параметры

INDEX

Перестраивает указанный индекс.

TABLE

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

SCHEMA

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

DATABASE

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

SYSTEM

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

имя

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

CONCURRENTLY

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

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

VERBOSE

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

Примечания

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

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

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

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

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

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

Переиндексирование партиционированных таблиц или партиционированных индексов не поддерживается. Вместо этого каждую партицию можно переиндексировать отдельно.

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

Перестроение индекса может помешать регулярной работе базы данных. Обычно 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 завершится ошибкой, но оставит после себя «нерабочий» новый индекс в дополнение к уже существующему. Этот индекс будет игнорироваться запросами, поскольку может быть неполным; однако он всё равно будет обновляться при изменении данных, что повлечет дополнительные издержки. Команда qsql \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 SYSTEM не поддерживает указание CONCURRENTLY, так как системные каталоги нельзя переиндексировать в неблокирующем режиме.

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

Примеры

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

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