Base de datos "congelada" en ALTER TABLE


15

Nuestro entorno de producción se congeló * esta mañana durante un tiempo al modificar una tabla, agregando una columna en realidad.

SQL ofensivo:ALTER TABLE cliente ADD COLUMN topicos character varying(20)[];

* Iniciar sesión en nuestro sistema requiere una selección de esa misma tabla, por lo que nadie podría iniciar sesión durante la tabla alternativa. De hecho, tuvimos que matar el proceso para permitir que el sistema reanudara las operaciones normales.


Estructura de la mesa:

CREATE TABLE cliente
(
  rut character varying(30) NOT NULL,
  nombre character varying(150) NOT NULL,
  razon_social character varying(150) NOT NULL,
  direccion character varying(200) NOT NULL,
  comuna character varying(100) NOT NULL,
  ciudad character varying(100) NOT NULL,
  codigo_pais character varying(3) NOT NULL,
  activo boolean DEFAULT true,
  id serial NOT NULL,
  stock boolean DEFAULT false,
  vigente boolean DEFAULT true,
  clase integer DEFAULT 1,
  plan integer DEFAULT 1,
  plantilla character varying(15) DEFAULT 'WAYPOINT'::character varying,
  facturable integer DEFAULT 1,
  toolkit integer DEFAULT 0,
  propietario integer DEFAULT 0,
  creacion timestamp without time zone DEFAULT now(),
  codelco boolean NOT NULL DEFAULT false,
  familia integer DEFAULT 0,
  enabled_machines boolean DEFAULT false,
  enabled_canbus boolean DEFAULT false,
  enabled_horometro boolean DEFAULT false,
  enabled_comap boolean DEFAULT false,
  enabled_frio boolean DEFAULT false,
  enabled_panico boolean DEFAULT false,
  enabled_puerta boolean DEFAULT false,
  enabled_rpm boolean DEFAULT false,
  enabled_supervisor integer DEFAULT 0,
  demo boolean,
  interno boolean,
  mqtt_enable boolean NOT NULL DEFAULT false,
  topicos character varying(20)[],
  CONSTRAINT pk_cliente PRIMARY KEY (rut),
  CONSTRAINT fk_cliente_familiaid FOREIGN KEY (familia)
      REFERENCES cliente_familia (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT pk_pais FOREIGN KEY (codigo_pais)
      REFERENCES pais (codigo) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT unique_id_cliente UNIQUE (id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE cliente
  OWNER TO waypoint;
GRANT ALL ON TABLE cliente TO waypoint;
GRANT ALL ON TABLE cliente TO waypointtx;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE cliente TO waypointtomcat;
GRANT SELECT ON TABLE cliente TO waypointphp;
GRANT SELECT ON TABLE cliente TO waypointpphppublic;
GRANT ALL ON TABLE cliente TO waypointsoporte;
GRANT SELECT, INSERT ON TABLE cliente TO waypointsalesforce;
GRANT SELECT ON TABLE cliente TO waypointadminuser;
GRANT SELECT ON TABLE cliente TO waypointagenda;
GRANT SELECT ON TABLE cliente TO waypointmachines;
GRANT SELECT ON TABLE cliente TO waypointreports;
GRANT SELECT ON TABLE cliente TO readonly;

CREATE INDEX index_cliente
  ON cliente
  USING btree
  (rut COLLATE pg_catalog."default");

CREATE INDEX index_cliente_activo
  ON cliente
  USING btree
  (activo);

CREATE INDEX index_cliente_id_activo
  ON cliente
  USING btree
  (id, activo);

CREATE INDEX index_cliente_rut_activo
  ON cliente
  USING btree
  (rut COLLATE pg_catalog."default", activo);


CREATE TRIGGER trigger_default_admin
  AFTER INSERT
  ON cliente
  FOR EACH ROW
  EXECUTE PROCEDURE crea_default_admin();

CREATE TRIGGER trigger_default_grupo
  AFTER INSERT
  ON cliente
  FOR EACH ROW
  EXECUTE PROCEDURE crea_default_clientegrupo();  

¿Debo deshabilitar CONSTRAINTS, TRIGGERS u otra cosa?

Tal vez alguna sintonización de DB?

¿Qué más debo proporcionar para un análisis más detallado?

Versión: PostgreSQL 9.4.5 en x86_64-unknown-linux-gnu, compilado por gcc (Debian 4.9.2-10) 4.9.2, 64 bits


Mientras se ejecuta una instrucción DDL, la tabla está bloqueada y no se puede acceder a ella. No hay nada que puedas hacer al respecto.
a_horse_with_no_name

bueno, no tan bueno como se esperaba, pero absolutamente comprensible;)
Gonzalo Vasquez

Respuestas:


8

Las operaciones DDL generalmente bloquean el objeto sobre el que están actuando, por lo que no deben realizarse fuera de las ventanas de mantenimiento planificadas (cuando los usuarios esperan interrupciones o el sistema esté completamente fuera de línea por un período de tiempo planificado): no hay nada que pueda hacer. sobre esto fácilmente 1 .

Algunas operaciones solo mantienen un bloqueo de escritura, por lo que su aplicación puede seguir sirviendo solicitudes que solo leen los objetos afectados.

La documentación parece bastante buena para enumerar qué bloqueos pueden tener las operaciones DDL.

Esta entrada de blog tiene un resumen que sugiere que agregar una columna puede ser una operación en línea si la columna es anulable y no tiene un valor predeterminado o una restricción única, aunque eso implica que la declaración que usted afirma debe haberse ejecutado sin bloqueos (como IIRC postgres el valor predeterminado de las columnas es NULLable a menos que indique explícitamente lo contrario). ¿Ejecutó alguna otra operación después de la columna de agregar? ¿Quizás crear un índice sobre él (que tomaría un bloqueo de escritura en la tabla por defecto)?

1 Algunos arreglos de replicación / agrupación / duplicación le permitirían actualizar una duplicación (pausar las actualizaciones durante el cambio y volver a reproducirlas después), cambiar a usar esa copia como la en vivo, y así sucesivamente hasta que se actualice cada copia, por lo que El tiempo de inactividad se limita al tiempo que se tarda en reproducir los cambios realizados durante la operación DDL. Sin embargo, las operaciones en vivo de este tipo no están exentas de riesgos, por lo que, a menos que no pueda, se recomienda que organice una ventana de mantenimiento adecuada para realizar y verificar las actualizaciones estructurales.


35

El comando que desea ejecutar toma un bloqueo de ACCESS EXCLUSIVE en la tabla, evitando el acceso a esa tabla. Pero la duración de este bloqueo debe ser de unos pocos milisegundos, ya que agregar una columna como la que desea agregar no requiere que la tabla se vuelva a escribir, solo requiere que se actualicen los metadatos.

Donde puede surgir el problema, y ​​le apuesto dólares a donas a que es el problema que está viendo, está en las prioridades de bloqueo. Alguien tiene un bloqueo débil, como el bloqueo ACCESS SHARE, en esa mesa, y están acampando indefinidamente (¿tal vez una conexión inactiva en la transacción que se ha filtrado? Alguien que abrió psql, inició una consulta en un modo de lectura repetible, y luego se fue de vacaciones?).

ADD COLUMN intenta tomar el ACCESS EXCLUSIVE que necesita, y hace cola detrás del primer bloqueo.

Ahora, todas las solicitudes de bloqueo futuras se ponen en cola detrás de la solicitud EXCLUSIVA DE ACCESO en espera.

Conceptualmente, las solicitudes de bloqueo entrantes que son compatibles con el bloqueo ya otorgado podrían saltar el ACCESS EXCLUSIVE en espera y otorgarse fuera de turno, pero no es así como lo hace PostgreSQL.

Necesita encontrar el proceso que mantiene el bloqueo débil de larga duración.

Puede hacer esto consultando la tabla pg_locks.

select * from pg_locks where 
    granted and relation = 'cliente'::regclass \x\g\x

Si hace esto mientras todo está bloqueado, debería obtener solo una respuesta (a menos que haya múltiples culpables de larga vida). Si hace esto después de que ya mató la AGREGAR COLUMNA, es posible que vea muchos bloqueos otorgados, pero si lo repite varias veces, debería haber uno o unos pocos que permanecen alrededor cada vez.

Luego puede tomar el PID que obtuvo de pg_lock y consultarlo con pg_stat_activity para ver qué está haciendo el delincuente:

select * from pg_stat_activity where pid=28731 \x\g\x

...

backend_start    | 2016-03-22 13:08:30.849405-07
xact_start       | 2016-03-22 13:08:36.797703-07
query_start      | 2016-03-22 13:08:36.799021-07
state_change     | 2016-03-22 13:08:36.824369-07
waiting          | f
state            | idle in transaction
backend_xid      |
backend_xmin     |
query            | select * from cliente limit 4;

Entonces, ejecutó una consulta, dentro de una transacción, y luego quedó inactiva sin cerrar la transacción. Ahora son las 13:13, por lo que han estado inactivos durante 5 minutos.


66
Esta respuesta me salvó la vida
Mahendra

1
También salvé el mío, la parte lock prioritiesfue muy buena, porque no he leído sobre eso en otros lugares, ¡gracias!
Edson Horacio Junior
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.