Наша производственная среда просто замерла сегодня утром на некоторое время, изменяя таблицу, фактически добавляя столбец.
Оскорбляющий 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-битная
postgresql
postgresql-9.4
alter-table
blocking
Гонсало Васкес
источник
источник
Ответы:
Операции DDL обычно блокируют объект, на который они воздействуют, поэтому их не следует выполнять за пределами плановых периодов обслуживания (когда ваши пользователи ожидают сбои или система будет полностью отключена в течение запланированного периода времени) - вы ничего не можете сделать об этом легко 1 .
Некоторые операции поддерживают только блокировку записи, поэтому ваше приложение может продолжать обслуживать запросы, которые читают только затронутые объекты.
Документация, кажется, довольно хорошо показывает список блокировок, которые могут удерживать операции DDL.
В этой записи блога есть сводка, которая предполагает, что добавление столбца может быть оперативной операцией, если столбец имеет значение NULL и не имеет значения по умолчанию или уникального ограничения, хотя это подразумевает, что утверждение, которое вы заявляете, должно быть выполнено без блокировок (как в публикации IIRC по умолчанию столбцы имеют значение NULLable, если вы явно не укажете иное). Вы выполняли какие-либо другие операции после столбца добавления? Возможно, создать для него индекс (который по умолчанию будет блокировать запись в таблицу)?
1 Некоторые механизмы репликации / кластеризации / зеркалирования позволяют обновлять зеркало (приостанавливая его обновление во время изменения и повторяя его после), переключаться на использование этой копии в качестве действующей и т. Д., Пока каждая копия не будет обновлена, поэтому время простоя ограничено временем, необходимым для воспроизведения изменений, внесенных во время операции DDL. Подобные операции в реальном времени не без риска, поэтому, если вы абсолютно не можете, рекомендуется вместо этого организовать правильное окно обслуживания для выполнения и проверки структурных обновлений.
источник
Команда, которую вы хотите выполнить, устанавливает блокировку ACCESS EXCLUSIVE на таблицу, предотвращая любой другой доступ к этой таблице. Но длительность этой блокировки должна составлять всего несколько миллисекунд, поскольку добавление столбца, подобного тому, который вы хотите добавить, не требует перезаписи таблицы, просто требуется обновление метаданных.
Где проблема может прийти, и я держу пари, что вы пончики, что это проблема, которую вы видите, находится в приоритетах блокировки. У кого-то есть слабая блокировка, такая как блокировка ACCESS SHARE, для этой таблицы, и они держат ее бесконечно (может быть, утечка соединения бездействия в транзакции? Кто-то, кто открыл psql, запустил запрос в режиме повторяющегося чтения, а потом уехал в отпуск?).
ADD COLUMN пытается получить ДОСТУПНЫЙ ЭКСКЛЮЗИВ, в котором он нуждается, и ставится в очередь за первой блокировкой.
Теперь все будущие запросы блокировки ставятся в очередь позади ожидающего запроса ACCESS EXCLUSIVE.
Концептуально входящие запросы на блокировку, которые совместимы с уже предоставленной блокировкой, могут перепрыгивать через ожидающий ACCESS EXCLUSIVE и предоставляться вне очереди, но PostgreSQL делает это не так.
Вам нужно найти процесс, который удерживает долгоживущий слабый замок.
Вы можете сделать это, запросив таблицу pg_locks.
Если вы делаете это, пока все заперто, вы должны получить только один ответ (если нет нескольких долгоживущих преступников). Если вы сделаете это после того, как уже убили ДОБАВИТЬ КОЛОННУ, то вы можете увидеть множество предоставленных блокировок, но если вы повторите это несколько раз, то должны появиться одна или несколько, которые остаются вокруг каждый раз.
Затем вы можете взять PID, полученный от pg_lock, и запросить его в pg_stat_activity, чтобы увидеть, что делает нарушитель:
...
Таким образом, он выполнил запрос внутри транзакции, а затем бездействовал, не закрывая транзакцию. Сейчас 13:13, поэтому они простаивают 5 минут.
источник
lock priorities
была очень хорошей, потому что я не читал об этом в других местах, спасибо!