¿Es seguro cancelar una consulta PostgreSQL ALTER TABLE que está esperando en un bloqueo?

10

Comenzamos una ALTER TABLEconsulta hace horas y solo recientemente nos dimos cuenta (a través de pg_stat_activity) que está esperando un bloqueo. Descubrimos la otra consulta que mantiene un bloqueo en la tabla que queremos modificar, y no la dejamos ir.

Nuestra consulta es una consulta "simple" (que cambia el tipo de datos de una columna), pero se ejecuta en una tabla masiva.

En lugar de matar el proceso que está reteniendo la cerradura, hemos decidido que preferimos matarlo ALTER TABLE.

Nos hicieron no envolver los ALTER TABLEen una transacción.

Según tengo entendido, el hecho de que nuestra consulta esté esperando un bloqueo significa que siempre ha estado esperando un bloqueo y nunca ha cambiado nada.

¿Es esto cierto? ¿Es seguro para nosotros cancelar por completo nuestra ALTER TABLEconsulta? ¿O es posible que la consulta ya haya modificado algo y cancelarla dejaría nuestra base de datos en algún estado intermedio?

PD: El plan es cancelarlo usando SELECT pg_cancel_backend(pid);. Si es una mala idea, avíseme.

JMTyler
fuente
1
Debería estar bien cancelar la TABLA ALTER. PostgreSQL tiene DDL transaccional, y debería dejarlo en el mismo estado que si no hubiera ejecutado ALTER TABLE en absoluto.
Josh Kupershmidt
Entonces, cuando dice que PostgreSQL tiene una transacción DDL, ¿eso significa que cualquier consulta de cambio de esquema se ejecuta esencialmente dentro de una transacción?
JMTyler
1
En su caso, ALTER TABLE se "ejecuta esencialmente dentro de una transacción", ya que usted dijo "No envolvimos ALTER TABLE en una transacción". Sin embargo, si quisieras, podrías escribir BEGIN; ALTER TABLE foo ...; ALTER TABLE bar ...; etc. COMETER; - esa es la característica asesina real de PostgreSQL que tiene DDL transaccional. Pero para su situación inmediata, sí, ALTER TABLE por sí solo se puede cancelar de forma segura y se revertirá como si nunca hubiera sucedido.
Josh Kupershmidt
¡Muchas gracias por sus rápidas respuestas! Esta es muy buena información. ¿Podría publicarlo como respuesta para que pueda marcarlo como aceptado?
JMTyler

Respuestas:

13

Según tengo entendido, el hecho de que nuestra consulta esté esperando un bloqueo significa que siempre ha estado esperando un bloqueo y nunca ha cambiado nada.

Correcto: si ve que pg_stat_activity.waiting es "verdadero" para una TABLA DE ALTERACIÓN, eso seguramente significa que está esperando pacientemente el bloqueo ACCESS EXCLUSIVE en su tabla de destino y su verdadero trabajo (reescribiendo la tabla si es necesario, cambiando los catálogos) , reconstrucción de índices, etc.) aún no ha comenzado.

¿Es seguro para nosotros cancelar por completo nuestra consulta ALTER TABLE? ¿O es posible que la consulta ya haya modificado algo y cancelarla dejaría nuestra base de datos en algún estado intermedio?

Cancelar consultas (o, de manera equivalente, deshacer una transacción) en PostgreSQL no tiene ningún peligro de corrupción de la base de datos que podría haber sido asustado en ciertas otras bases de datos (por ejemplo, la advertencia aterradora al final de esta página). Es por eso que los que no son superusuarios son, en versiones recientes, libres de usar pg_cancel_backend()y pg_terminate_backend()eliminar sus propias consultas que se ejecutan en otros servidores; son seguros de usar sin preocuparse por la corrupción de la base de datos. Después de todo, PostgreSQL tiene que estar preparado para lidiar con cualquier proceso que se elimine, por ejemplo, SIGKILL del asesino OOM, el apagado del servidor, etc. Para eso está el registro WAL .

También es posible que haya visto que en PostgreSQL, es posible realizar la mayoría de los comandos DDL anidados dentro de una transacción (multi-declaración), por ejemplo

BEGIN;
ALTER TABLE foo ...;
ALTER TABLE bar ...;
-- more stuff
COMMIT; -- or ROLLBACK; if you've changed your mind

(Impresionante para asegurarse de que las migraciones de esquemas se realicen juntas o no). Sin embargo, usted dijo:

Nos hicieron no envolver los ALTER TABLEen una transacción.

Eso está bien para un solo comando: de los documentos ,

PostgreSQL en realidad trata cada declaración SQL como ejecutada dentro de una transacción. Si no emite un comando BEGIN, cada instrucción individual tiene un BEGIN implícito y (si tiene éxito) COMMIT envuelto alrededor de él. Un grupo de declaraciones rodeadas por BEGIN y COMMIT a veces se denomina bloque de transacción.

Por lo tanto, cancelar eso ALTER TABLE, ya sea a través de pg_cancel_backend()un Ctrl-C emitido desde el indicador de control psql, tendrá un efecto similar al que hubiera hecho

BEGIN;
ALTER TABLE ... ;
ROLLBACK;

(aunque como es de esperar, cancelar eso costoso ALTER TABLEpuede salvar la base de datos de una gran cantidad de trabajo innecesario si de ROLLBACKtodos modos lo hará ).

Josh Kupershmidt
fuente
5

Para elaborar sobre la respuesta correcta y excelente de Josh:

¿Es seguro para nosotros cancelar por completo nuestra consulta ALTER TABLE?

Si.

Sería seguro incluso si estuviera en el medio de reescribir la tabla .

Si quisieras, podrías simplemente apagar todo el servidor PostgreSQL, o de hecho la máquina en la que se ejecuta, reiniciarlo, y todo estaría bien. DDL en PostgreSQL es transaccional y a prueba de fallos.

Las operaciones DDL se registran a través de WAL y se garantiza que pueden revertirse o completarse tras la recuperación después de un bloqueo o un aborto.

Craig Ringer
fuente
3
Solo una nota sobre "podría simplemente apagar todo el servidor PostgreSQL, o de hecho la máquina en la que se ejecuta, reiniciarlo, y todo estaría bien" - bastante cierto siempre que tenga un hardware confiable que no mienta sobre fsync , wiki.postgresql.org/wiki/Reliable_Writes
Josh Kupershmidt
2
@JoshKupershmidt Claro, pero eso no es específico de DDL. Si tiene problemas de sincronización, entonces no es seguro para todo .
Craig Ringer