Database "congelato" su ALTER TABLE


15

Il nostro ambiente di produzione è rimasto bloccato * questa mattina per un po 'quando si modifica una tabella, aggiungendo effettivamente una colonna.

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

* L'accesso al nostro sistema richiede una selezione dalla stessa tabella, quindi nessuno potrebbe accedere durante la modifica della tabella. In realtà abbiamo dovuto terminare il processo per consentire al sistema di riprendere le normali operazioni.


Struttura della tabella:

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();  

Devo disabilitare VINCITORI, GRILLETTI o qualcos'altro?

Forse qualche sintonizzazione DB?

Cos'altro dovrei fornire per ulteriori analisi?

Versione: PostgreSQL 9.4.5 su x86_64-unknown-linux-gnu, compilato da gcc (Debian 4.9.2-10) 4.9.2, 64-bit


Finché è in esecuzione un'istruzione DDL, la tabella è bloccata e non è possibile accedervi. Non c'è niente che tu possa fare al riguardo.
a_horse_with_no_name

beh, non così bello come ci si aspetterebbe, ma assolutamente comprensibile;)
Gonzalo Vasquez,

Risposte:


8

Le operazioni DDL di solito bloccano l'oggetto su cui agiscono, quindi non dovrebbero essere eseguite al di fuori delle finestre di manutenzione pianificata (quando gli utenti si aspettano interruzioni o il sistema sarà completamente offline per un periodo di tempo pianificato) - non c'è nulla che tu possa fare su questo facilmente 1 .

Alcune operazioni mantengono solo un blocco in scrittura, quindi l'applicazione può continuare a servire le richieste che leggono solo gli oggetti interessati.

La documentazione sembra abbastanza buona nel elencare quali blocchi potrebbero essere trattenuti dalle operazioni DDL.

Questo post di blog ha un riepilogo che suggerisce che l'aggiunta di una colonna può essere un'operazione online se la colonna è nullable e non ha un valore predefinito o un vincolo univoco, sebbene ciò implichi che l'istruzione dichiarata dovrebbe essere stata eseguita senza blocchi (come Postgres IIRC il valore predefinito delle colonne è NULLable, a meno che non sia indicato esplicitamente diversamente). Hai eseguito altre operazioni dopo la colonna aggiungi? Forse la creazione di un indice su di esso (che per impostazione predefinita richiederebbe un blocco di scrittura sulla tabella)?

1 Alcune disposizioni di replica / clustering / mirroring consentono di aggiornare un mirror (sospendendo gli aggiornamenti durante la modifica e riproducendoli dopo), passare a utilizzare quella copia come quella live e così via fino a quando ogni copia non viene aggiornata, quindi il tempo di inattività è limitato al tempo necessario per riprodurre le modifiche apportate durante l'operazione DDL. Tuttavia, le operazioni in tempo reale non sono prive di rischi, quindi a meno che non sia assolutamente possibile, si consiglia di organizzare una finestra di manutenzione adeguata per eseguire e verificare gli aggiornamenti strutturali.


35

Il comando che si desidera eseguire richiede un blocco ACCESS EXCLUSIVE sulla tabella, impedendo a tutti gli altri accessi a quella tabella. Ma la durata di questo blocco dovrebbe essere di pochi millisecondi, poiché l'aggiunta di una colonna come quella che si desidera aggiungere non richiede la riscrittura della tabella, richiede solo l'aggiornamento dei metadati.

Dove può sorgere il problema, e scommetto dollari a ciambelle che è il problema che stai vedendo, è nelle priorità di blocco. Qualcuno ha un blocco debole, come il blocco ACCESS SHARE, su quel tavolo e ci si accampa indefinitamente (forse una connessione inattiva in transazione che è stata trapelata? Qualcuno che ha aperto psql, ha avviato una query in una modalità di lettura ripetibile, e poi è andato in vacanza?).

ADD COLUMN tenta di prendere l'ACCESSO ESCLUSIVO di cui ha bisogno e si mette in coda dietro il primo lucchetto.

Ora tutte le future richieste di blocco si mettono in coda dietro la richiesta ACCESSO ESCLUSIVO in attesa.

Concettualmente, le richieste di blocco in entrata compatibili con il blocco già concesso potrebbero saltare sull'ESCLUSIVO ACCESSO in attesa ed essere concesse fuori turno, ma non è così che PostgreSQL lo fa.

È necessario trovare il processo che sta trattenendo il blocco debole di lunga durata.

Puoi farlo interrogando la tabella pg_locks.

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

Se lo fai mentre tutto è bloccato, dovresti ottenere una sola risposta (a meno che non ci siano più colpevoli di lunga durata). Se lo fai dopo aver già ucciso ADD COLUMN, potresti vedere molti lucchetti concessi, ma se lo ripeti alcune volte dovrebbero essercene uno o pochi che rimangono ogni volta.

È quindi possibile prendere il PID ottenuto da pg_lock e interrogarlo in pg_stat_activity per vedere cosa sta facendo l'autore del reato:

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;

Quindi, ha eseguito una query, all'interno di una transazione, quindi è rimasto inattivo senza mai chiudere la transazione. Sono le 13:13, quindi sono rimasti inattivi per 5 minuti.


6
Questa risposta mi ha salvato la vita
Mahendra,

1
Anche il mio è stato salvato, la parte è lock prioritiesstata molto buona, perché non l'ho letto in altri posti, grazie!
Edson Horacio Junior,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.