REINDEX

REINDEX — reconstruye índices

Synopsis

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

donde option puede ser uno de:

    CONCURRENTLY [ boolean ]
    TABLESPACE new_tablespace
    VERBOSE [ boolean ]

Descripción

REINDEX reconstruye un índice utilizando los datos almacenados en la tabla del índice, reemplazando la copia antigua del índice. Existen varios escenarios en los que se debe usar REINDEX:

  • Un índice se ha corrompido y ya no contiene datos válidos. Aunque en teoría esto no debería suceder nunca, en la práctica los índices pueden corromperse debido a errores de software o fallas de hardware. REINDEX proporciona un método de recuperación.

  • Un índice se ha vuelto bloated (hinchado), es decir, contiene muchas páginas vacías o casi vacías. Esto puede ocurrir con índices B-tree en PostgreSQL bajo ciertos patrones de acceso poco comunes. REINDEX proporciona una forma de reducir el consumo de espacio del índice escribiendo una nueva versión del índice sin las páginas muertas. Consulta Section 24.2 para más información.

  • Has modificado un parámetro de almacenamiento (como fillfactor) para un índice, y deseas asegurarte de que el cambio haya surtido pleno efecto.

  • Si la creación de un índice falla con la opción CONCURRENTLY, este índice queda como inválido. Estos índices son inútiles, pero puede ser conveniente usar REINDEX para reconstruirlos. Ten en cuenta que solo REINDEX INDEX es capaz de realizar una reconstrucción concurrente en un índice inválido.

Parámetros

INDEX

Recrea el índice especificado. Esta forma de REINDEX no se puede ejecutar dentro de un bloque de transacción cuando se usa con un índice particionado.

TABLE

Recrea todos los índices de la tabla especificada. Si la tabla tiene una tabla secundaria TOAST, esta también se reindexa. Esta forma de REINDEX no se puede ejecutar dentro de un bloque de transacción cuando se usa con una tabla particionada.

SCHEMA

Recrea todos los índices del esquema especificado. Si una tabla de este esquema tiene una tabla secundaria TOAST, esta también se reindexa. Los índices en catálogos compartidos del sistema también se procesan. Esta forma de REINDEX no se puede ejecutar dentro de un bloque de transacción.

DATABASE

Recrea todos los índices dentro de la base de datos actual, excepto los catálogos del sistema. Los índices en los catálogos del sistema no se procesan. Esta forma de REINDEX no se puede ejecutar dentro de un bloque de transacción.

SYSTEM

Recrea todos los índices de los catálogos del sistema dentro de la base de datos actual. Se incluyen los índices en catálogos del sistema compartidos. Los índices en las tablas de usuario no se procesan. Esta forma de REINDEX no se puede ejecutar dentro de un bloque de transacción.

name

El nombre del índice, tabla o base de datos específica que se va a reindexar. Los nombres de índices y tablas pueden estar calificados por esquema. Actualmente, REINDEX DATABASE and REINDEX SYSTEM solo pueden reindexar la base de datos actual. Su parámetro es opcional y debe coincidir con el nombre de la base de datos actual.

CONCURRENTLY

Cuando se utiliza esta opción, PostgreSQL reconstruirá el índice sin adquirir ningún bloqueo que impida inserciones, actualizaciones o eliminaciones concurrentes en la tabla; mientras que una reconstrucción de índice estándar bloquea las escrituras (pero no las lecturas) en la tabla hasta que finaliza. Hay varias advertencias a tener en cuenta al usar esta opción: consulta Rebuilding Indexes Concurrently más abajo.

Para tablas temporales, REINDEX siempre es no concurrente, ya que ninguna otra sesión puede acceder a ellas, y la reindexación no concurrente es más económica.

TABLESPACE

Especifica que los índices se reconstruirán en un nuevo tablespace.

VERBOSE

Imprime un informe de progreso a medida que se reindexa cada índice a nivel INFO.

boolean

Especifica si la opción seleccionada debe activarse o desactivarse. Puedes escribir TRUE, ON o 1 para activar la opción, y FALSE, OFF o 0 para desactivarla. El valor boolean también se puede omitir, en cuyo caso se asume TRUE.

new_tablespace

El tablespace donde se reconstruirán los índices.

Notas

Si sospechas que hay corrupción en un índice de una tabla de usuario, puedes simplemente reconstruir ese índice, o todos los índices de la tabla, utilizando REINDEX INDEX o REINDEX TABLE.

Las cosas son más difíciles si necesitas recuperarte de la corrupción de un índice en una tabla del sistema. En este caso es importante que el sistema no haya utilizado ninguno de los índices sospechosos. (De hecho, en este tipo de escenario podrías encontrar que los procesos del servidor se caen inmediatamente al iniciarse, debido a la dependencia de los índices corrompidos). Para recuperarse de forma segura, el servidor debe iniciarse con la opción -P, que le impide utilizar los índices para las búsquedas en los catálogos del sistema.

Una forma de hacer esto es detener el servidor e iniciar un servidor PostgreSQL en modo monousuario con la opción -P incluida en su línea de comandos. Luego, se puede ejecutar REINDEX DATABASE, REINDEX SYSTEM, REINDEX TABLE o REINDEX INDEX, dependiendo de cuánto quieras reconstruir. En caso de duda, utiliza REINDEX SYSTEM para seleccionar la reconstrucción de todos los índices del sistema en la base de datos. A continuación, sal de la sesión del servidor en modo monousuario y reinicia el servidor regular. Consulta la página de referencia de postgres para obtener más información sobre cómo interactuar con la interfaz del servidor en modo monousuario.

Alternativamente, se puede iniciar una sesión de servidor regular con -P incluido en sus opciones de línea de comandos. El método para hacer esto varía según el cliente, pero en todos los clientes basados en libpq, es posible establecer la variable de entorno PGOPTIONS en -P antes de iniciar el cliente. Ten en cuenta que aunque este método no requiere bloquear a otros clientes, podría ser aconsejable evitar que otros usuarios se conecten a la base de datos dañada hasta que se hayan completado las reparaciones.

REINDEX es similar a eliminar y recrear el índice, en el sentido de que los contenidos del índice se reconstruyen desde cero. Sin embargo, las consideraciones de bloqueo son bastante diferentes. REINDEX bloquea las escrituras pero no las lecturas de la tabla padre del índice. También adquiere un bloqueo ACCESS EXCLUSIVE en el índice específico que se está procesando, lo que bloqueará las lecturas que intenten utilizar ese índice. En particular, el planificador de consultas intenta adquirir un bloqueo ACCESS SHARE en cada índice de la tabla, independientemente de la consulta, por lo que REINDEX bloquea prácticamente cualquier consulta excepto algunas consultas preparadas cuyo plan ha sido almacenado en caché y que no utilizan este índice. En contraste, DROP INDEX adquiere momentáneamente un bloqueo ACCESS EXCLUSIVE en la tabla padre, bloqueando tanto las escrituras como las lecturas. El subsiguiente CREATE INDEX bloquea las escrituras pero no las lecturas; dado que el índice no está allí, ninguna lectura intentará utilizarlo, lo que significa que no habrá bloqueo, pero las lecturas podrían verse forzadas a realizar costosos escaneos secuenciales.

Mientras se ejecuta REINDEX, la variable de entorno search_path se cambia temporalmente a pg_catalog, pg_temp.

Reindexar un único índice o tabla requiere tener el privilegio MAINTAIN en la tabla. Ten en cuenta que aunque REINDEX en un índice o tabla particionada requiere tener el privilegio MAINTAIN en la tabla particionada, dichos comandos omiten las comprobaciones de privilegios al procesar las particiones individuales. Reindexar un esquema o base de datos requiere ser el propietario de ese esquema o base de datos o tener los privilegios del rol pg_maintain. Ten en cuenta específicamente que por lo tanto es posible para los usuarios que no son superusuarios reconstruir índices de tablas que pertenecen a otros usuarios. Sin embargo, como excepción especial, REINDEX DATABASE, REINDEX SCHEMA y REINDEX SYSTEM omitirán los índices en los catálogos compartidos a menos que el usuario tenga el privilegio MAINTAIN en el catálogo.

La reindexación de índices particionados o tablas particionadas es compatible con REINDEX INDEX o REINDEX TABLE, respectivamente. Cada partición de la relación particionada especificada se reindexa en una transacción independiente. Esos comandos no se pueden utilizar dentro de un bloque de transacción cuando se trabaja en una tabla o índice particionado.

Cuando se utiliza la cláusula TABLESPACE con REINDEX en un índice o tabla particionada, solo se actualizan las referencias de tablespace de las particiones hoja. Como los índices particionados no se actualizan, se recomienda utilizar por separado ALTER TABLE ONLY en ellos para que las nuevas particiones asociadas hereden el nuevo tablespace. En caso de fallo, es posible que no se hayan movido todos los índices al nuevo tablespace. Volver a ejecutar el comando reconstruirá todas las particiones hoja y moverá los índices previamente no procesados al nuevo tablespace.

Si se utiliza SCHEMA, DATABASE o SYSTEM con TABLESPACE, se omiten las relaciones del sistema y se generará una única advertencia (WARNING). Los índices en las tablas TOAST se reconstruyen, pero no se mueven al nuevo tablespace.

Reconstrucción de índices de forma concurrente

La reconstrucción de un índice puede interferir con la operación regular de una base de datos. Normalmente, PostgreSQL bloquea la tabla cuyo índice se reconstruye contra escrituras y realiza la construcción completa del índice con un único escaneo de la tabla. Otras transacciones aún pueden leer la tabla, pero si intentan insertar, actualizar o eliminar filas en la tabla, se bloquearán hasta que finalice la reconstrucción del índice. Esto podría tener un efecto grave si el sistema es una base de datos de producción activa. Las tablas muy grandes pueden tardar muchas horas en ser indexadas, e incluso para tablas más pequeñas, una reconstrucción de índice puede bloquear a los escritores durante períodos que son inaceptablemente largos para un sistema de producción.

PostgreSQL admite la reconstrucción de índices con un bloqueo mínimo de las escrituras. Este método se invoca especificando la opción CONCURRENTLY de REINDEX. Cuando se utiliza esta opción, PostgreSQL debe realizar dos escaneos de la tabla para cada índice que deba reconstruirse y esperar a la finalización de todas las transacciones existentes que potencialmente podrían utilizar el índice. Este método requiere más trabajo total que una reconstrucción de índice estándar y tarda significativamente más tiempo en completarse, ya que necesita esperar a las transacciones no finalizadas que podrían modificar el índice. Sin embargo, dado que permite que continúen las operaciones normales mientras se reconstruye el índice, este método es útil para reconstruir índices en un entorno de producción. Por supuesto, la carga adicional de CPU, memoria y E/S impuesta por la reconstrucción del índice puede ralentizar otras operaciones.

Los siguientes pasos ocurren en una reindexación concurrente. Cada paso se ejecuta en una transacción independiente. Si hay múltiples índices que reconstruir, entonces cada paso recorre todos los índices antes de pasar al siguiente paso.

  1. Se añade una nueva definición de índice transitorio al catálogo pg_index. Esta definición se utilizará para reemplazar al índice antiguo. Se adquiere un bloqueo SHARE UPDATE EXCLUSIVE a nivel de sesión en los índices que se están reindexando, así como en sus tablas asociadas para evitar cualquier modificación del esquema mientras se procesa.

  2. Se realiza una primera pasada para construir el índice para cada nuevo índice. Una vez que el índice está construido, su flag pg_index.indisready se cambia a true para que esté listo para inserciones, haciéndolo visible para otras sesiones una vez que la transacción que realizó la construcción haya finalizado. Este paso se realiza en una transacción independiente para cada índice.

  3. A continuación, se realiza una segunda pasada para añadir las tuplas que se añadieron mientras se ejecutaba la primera pasada. Este paso también se realiza en una transacción independiente para cada índice.

  4. Todas las restricciones que hacen referencia al índice se modifican para hacer referencia a la nueva definición del índice, y se cambian los nombres de los índices. En este punto, pg_index.indisvalid se cambia a true para el nuevo índice y a false para el antiguo, y se realiza una invalidación de caché que hace que se invaliden todas las sesiones que hacían referencia al índice antiguo.

  5. Los índices antiguos tienen su flag pg_index.indisready cambiado a false para evitar cualquier nueva inserción de tuplas, después de esperar a que se completen las consultas en ejecución que podrían hacer referencia al índice antiguo.

  6. Se eliminan los índices antiguos. Se liberan los bloqueos de sesión SHARE UPDATE EXCLUSIVE para los índices y la tabla.

Si surge un problema al reconstruir los índices, como una violación de unicidad en un índice único, el comando REINDEX fallará, pero dejará un nuevo índice inválido además del preexistente. Este índice se ignorará para fines de consulta porque podría estar incompleto; sin embargo, seguirá consumiendo sobrecarga de actualización. El comando \d de psql informará de dicho índice como INVALID:

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

Si el índice marcado como INVALID tiene el sufijo _ccnew, entonces corresponde al índice transitorio creado durante la operación concurrente, y el método de recuperación recomendado es eliminarlo utilizando DROP INDEX, y luego intentar REINDEX CONCURRENTLY de nuevo. Si el índice inválido tiene en cambio el sufijo _ccold, corresponde al índice original que no pudo ser eliminado; el método de recuperación recomendado es simplemente eliminar dicho índice, ya que la reconstrucción propiamente dicha ha sido exitosa. Se puede añadir un número distinto de cero al sufijo de los nombres de los índices inválidos para mantenerlos únicos, como _ccnew1, _ccold2, etc.

Las construcciones de índices normales permiten que se realicen simultáneamente otras construcciones de índices normales en la misma tabla, pero solo puede ocurrir una construcción de índice concurrente en una tabla a la vez. En ambos casos, no se permite ningún otro tipo de modificación del esquema en la tabla mientras tanto. Otra diferencia es que un comando regular REINDEX TABLE o REINDEX INDEX se puede realizar dentro de un bloque de transacción, pero REINDEX CONCURRENTLY no.

Al igual que cualquier transacción de larga duración, REINDEX en una tabla puede afectar a qué tuplas pueden ser eliminadas por un VACUUM concurrente en cualquier otra tabla.

REINDEX SYSTEM no admite CONCURRENTLY debido a que los catálogos del sistema no se pueden reindexar de forma concurrente.

Además, los índices para restricciones de exclusión no se pueden reindexar de forma concurrente. Si dicho índice se nombra directamente en este comando, se lanzará un error. Si una tabla o base de datos con índices de restricciones de exclusión se reindexa de forma concurrente, esos índices se omitirán. (Es posible reindexar dichos índices sin la opción CONCURRENTLY).

Cada proceso backend que ejecute REINDEX informará de su progreso en la vista pg_stat_progress_create_index. Consulta Section 27.4.4 para más detalles.

Ejemplos

Reconstruye un único índice:

REINDEX INDEX my_index;

Reconstruye todos los índices de la tabla my_table:

REINDEX TABLE my_table;

Reconstruye todos los índices en una base de datos en particular, sin confiar en que los índices del sistema ya sean válidos:

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

Reconstruye los índices para una tabla, sin bloquear las operaciones de lectura y escritura en las relaciones involucradas mientras la reindexación está en progreso:

REINDEX TABLE CONCURRENTLY my_broken_table;

Compatibilidad

No existe el comando REINDEX en el estándar SQL.

Véase también

CREATE INDEX, DROP INDEX, reindexdb, Section 27.4.4