База данных «заморожена» на ALTER TABLE


15

Наша производственная среда просто замерла сегодня утром на некоторое время, изменяя таблицу, фактически добавляя столбец.

Оскорбляющий SQL:ALTER TABLE cliente ADD COLUMN topicos character varying(20)[];

* Для входа в нашу систему требуется выбрать из той же таблицы, чтобы никто не мог войти во время изменения таблицы. На самом деле нам пришлось убить процесс, чтобы система возобновила нормальную работу.


Структура таблицы:

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

Должен ли я отключить ограничения, триггеры или что-то еще?

Возможно какая-нибудь БД Тюнинг?

Что еще я должен предоставить для дальнейшего анализа?

Версия: PostgreSQL 9.4.5 для x86_64-unknown-linux-gnu, скомпилированная gcc (Debian 4.9.2-10) 4.9.2, 64-битная


Пока выполняется оператор DDL, таблица заблокирована и недоступна. С этим ничего не поделаешь.
a_horse_with_no_name

ну, не так хорошо, как ожидалось, но абсолютно понятно;)
Гонсало Васкес

Ответы:


8

Операции DDL обычно блокируют объект, на который они воздействуют, поэтому их не следует выполнять за пределами плановых периодов обслуживания (когда ваши пользователи ожидают сбои или система будет полностью отключена в течение запланированного периода времени) - вы ничего не можете сделать об этом легко 1 .

Некоторые операции поддерживают только блокировку записи, поэтому ваше приложение может продолжать обслуживать запросы, которые читают только затронутые объекты.

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

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

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


35

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

Где проблема может прийти, и я держу пари, что вы пончики, что это проблема, которую вы видите, находится в приоритетах блокировки. У кого-то есть слабая блокировка, такая как блокировка ACCESS SHARE, для этой таблицы, и они держат ее бесконечно (может быть, утечка соединения бездействия в транзакции? Кто-то, кто открыл psql, запустил запрос в режиме повторяющегося чтения, а потом уехал в отпуск?).

ADD COLUMN пытается получить ДОСТУПНЫЙ ЭКСКЛЮЗИВ, в котором он нуждается, и ставится в очередь за первой блокировкой.

Теперь все будущие запросы блокировки ставятся в очередь позади ожидающего запроса ACCESS EXCLUSIVE.

Концептуально входящие запросы на блокировку, которые совместимы с уже предоставленной блокировкой, могут перепрыгивать через ожидающий ACCESS EXCLUSIVE и предоставляться вне очереди, но PostgreSQL делает это не так.

Вам нужно найти процесс, который удерживает долгоживущий слабый замок.

Вы можете сделать это, запросив таблицу pg_locks.

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

Если вы делаете это, пока все заперто, вы должны получить только один ответ (если нет нескольких долгоживущих преступников). Если вы сделаете это после того, как уже убили ДОБАВИТЬ КОЛОННУ, то вы можете увидеть множество предоставленных блокировок, но если вы повторите это несколько раз, то должны появиться одна или несколько, которые остаются вокруг каждый раз.

Затем вы можете взять PID, полученный от pg_lock, и запросить его в pg_stat_activity, чтобы увидеть, что делает нарушитель:

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;

Таким образом, он выполнил запрос внутри транзакции, а затем бездействовал, не закрывая транзакцию. Сейчас 13:13, поэтому они простаивают 5 минут.


6
Этот ответ спас мне жизнь
Махендра

1
Спасла и мою, часть про lock prioritiesбыла очень хорошей, потому что я не читал об этом в других местах, спасибо!
Эдсон Орасио Джуниор
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.