우리의 생산 환경은 실제로 아침에 테이블을 변경하고 실제로 열을 추가 할 때 잠시 동안 얼어 붙었습니다 *.
위반 SQL :ALTER TABLE cliente ADD COLUMN topicos character varying(20)[];
* 시스템에 로그인하려면 동일한 테이블에서 선택해야하므로 alter 테이블 중에 아무도 로그인 할 수 없습니다. 실제로 시스템이 정상 작동을 재개 할 수 있도록 프로세스를 종료해야했습니다.
테이블 구조 :
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();
제약 조건, 트리거 또는 다른 기능을 비활성화해야합니까?
아마도 DB 튜닝?
추가 분석을 위해 무엇을 더 제공해야합니까?
버전 : gcc (Debian 4.9.2-10) 4.9.2, 64 비트로 컴파일 된 x86_64-unknown-linux-gnu의 PostgreSQL 9.4.5
답변
DDL 작업은 일반적으로 작업중인 개체를 잠그므로 계획된 유지 관리 기간 (사용자가 중단을 예상하거나 시스템이 계획된 시간 동안 완전히 오프라인 상태가 될 것으로 예상되는 경우) 외부에서 수행하면 안됩니다. 이것에 대해 쉽게 1 .
일부 작업은 쓰기 잠금 만 유지하므로 응용 프로그램은 영향을받는 개체 만 읽는 요청을 계속 제공 할 수 있습니다.
이 문서는 DDL 작업에서 보유 할 수있는 잠금을 나열하는 데 매우 적합합니다.
이 블로그 항목 에는 컬럼이 널 입력 가능하고 기본값이나 고유 제한 조건이없는 경우 컬럼 추가가 온라인 조작이 될 수 있음을 나타내는 요약이 있습니다. 명시 적으로 달리 명시하지 않는 한 열의 기본값은 NULL입니다. 추가 열 이후에 다른 작업을 실행 했습니까? 아마도 인덱스를 생성 할 것입니까 (기본적으로 테이블에 대한 쓰기 잠금이 필요합니까)?
1 일부 복제 / 클러스터링 / 미러링 배열을 사용하면 미러를 업데이트하고 (변경 중 업데이트를 일시 중지 한 후 다시 재생) 각 복사본이 업데이트 될 때까지 해당 복사본을 라이브 복사본으로 사용하도록 전환 할 수 있습니다. 다운 타임은 DDL 조작 중에 작성된 변경 사항을 재생하는 데 걸리는 시간으로 제한됩니다. 그러나 이와 같은 라이브 작업은 위험하지 않으므로 절대적으로 불가능한 경우가 아니라면 구조 업데이트를 수행하고 확인하기 위해 적절한 유지 관리 기간을 마련하는 것이 좋습니다.
답변
실행하려는 명령은 테이블에서 ACCESS EXCLUSIVE 잠금을 수행하여 해당 테이블에 대한 다른 모든 액세스를 방지합니다. 그러나 추가하려는 열과 같은 열을 추가 할 때는 테이블을 다시 쓰지 않아도되고 메타 데이터 만 업데이트하면되므로이 잠금 기간은 몇 밀리 초에 불과합니다.
문제가 발생할 수있는 곳과 도넛에 돈을 걸고 그것이 당신이보고있는 문제라고 생각하면 잠금 우선 순위에 있습니다. 누군가가 해당 테이블에 ACCESS SHARE 잠금과 같은 약한 잠금을 가지고 있으며 무제한으로 캠핑하고 있습니다. 그리고 휴가를 갔다?).
ADD COLUMN은 필요한 ACCESS EXCLUSIVE를 가져 오려고 시도하며 첫 번째 잠금 뒤에 대기합니다.
이제 모든 향후 잠금 요청이 대기중인 ACCESS EXCLUSIVE 요청 뒤에 대기합니다.
개념적으로, 이미 부여 된 잠금과 호환되는 들어오는 잠금 요청은 대기중인 액세스 독점을 뛰어 넘을 수 있으며 그 결과는 PostgreSQL이하는 방식이 아닙니다.
오래 지속되는 약한 잠금을 유지하고있는 프로세스를 찾아야합니다.
pg_locks 테이블을 쿼리하면됩니다.
select * from pg_locks where
granted and relation = 'cliente'::regclass \x\g\x
모든 것이 잠겨있는 동안이 작업을 수행하면 하나의 답변 만 얻어야합니다 (오래 오랜 수명을 유지하는 범인이없는 경우). ADD COLUMN을 이미 종료 한 후이 작업을 수행하면 잠금이 많이 부여 될 수 있지만 몇 번 반복하면 매번 주위에 하나 또는 몇 개가 있어야합니다.
그런 다음 pg_lock에서 가져온 PID를 가져 와서 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 분 동안 유휴 상태입니다.