Cơ sở dữ liệu bị đóng băng cứng trên ALTER TABLE


15

Môi trường sản xuất của chúng tôi chỉ đóng băng * sáng nay một lúc khi thay đổi bảng, thêm một cột thực sự.

Vi phạm SQL:ALTER TABLE cliente ADD COLUMN topicos character varying(20)[];

* Đăng nhập vào hệ thống của chúng tôi yêu cầu chọn từ cùng một bảng, vì vậy không ai có thể đăng nhập trong bảng thay đổi. Chúng tôi thực sự đã phải giết quá trình để cho phép hệ thống tiếp tục hoạt động bình thường.


Cấu trúc bảng:

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

Tôi có nên vô hiệu hóa CONSTRAINTS, TRIGGERS hoặc thứ gì khác không?

Có lẽ bất kỳ điều chỉnh DB?

Những gì khác tôi nên cung cấp để phân tích thêm?

Phiên bản: PostgreSQL 9.4.5 trên x86_64-unknown-linux-gnu, được biên dịch bởi gcc (Debian 4.9.2-10) 4.9.2, 64-bit


Miễn là câu lệnh DDL đang chạy, bảng sẽ bị khóa và không thể truy cập được. Không có gì bạn có thể làm về điều đó.
a_horse_with_no_name

tốt, không như es mong đợi, nhưng hoàn toàn dễ hiểu;)
Gonzalo Vasquez

Câu trả lời:


8

Các hoạt động DDL thường khóa đối tượng mà chúng đang hành động, do đó không nên được thực hiện bên ngoài các cửa sổ bảo trì theo kế hoạch (khi người dùng của bạn đang mong đợi sự gián đoạn hoặc hệ thống hoàn toàn ngoại tuyến trong một khoảng thời gian theo kế hoạch) - bạn không thể làm gì về điều này dễ dàng 1 .

Một số thao tác chỉ giữ khóa ghi, vì vậy ứng dụng của bạn có thể tiếp tục phục vụ các yêu cầu chỉ đọc các đối tượng bị ảnh hưởng.

Tài liệu này có vẻ khá tốt trong việc liệt kê những khóa nào có khả năng được giữ bởi các hoạt động DDL.

Mục blog này có một bản tóm tắt cho thấy việc thêm một cột có thể là một hoạt động trực tuyến nếu cột đó là null và không có giá trị mặc định hoặc ràng buộc duy nhất, mặc dù điều đó ngụ ý rằng câu lệnh mà bạn nên chạy mà không bị khóa (như các bài đăng của IIRC mặc định các cột là NULLable trừ khi bạn nói rõ ràng khác). Bạn đã chạy bất kỳ hoạt động khác sau khi thêm cột? Có lẽ tạo một chỉ mục theo nó (mặc định sẽ có một khóa ghi trên bảng)?

1 Một số sắp xếp sao chép / phân cụm / phản chiếu sẽ cho phép bạn cập nhật bản sao (tạm dừng cập nhật cho nó trong khi thay đổi và phát lại chúng sau), chuyển sang sử dụng bản sao đó như bản sao trực tiếp, và cứ thế cho đến khi mỗi bản sao được cập nhật, vì vậy thời gian chết được giới hạn trong thời gian cần thiết để phát lại các thay đổi được thực hiện trong hoạt động DDL. Các hoạt động trực tiếp như thế không phải là không có rủi ro, vì vậy trừ khi bạn hoàn toàn không thể khuyên bạn thay vào đó hãy sắp xếp một cửa sổ bảo trì thích hợp để thực hiện và xác minh các cập nhật cấu trúc.


35

Lệnh bạn muốn chạy sẽ thực hiện khóa ACCESS EXCLUSIVE trên bàn, ngăn tất cả các quyền truy cập khác vào bảng đó. Nhưng thời lượng của khóa này chỉ là vài mili giây, vì việc thêm một cột như cột bạn muốn thêm không yêu cầu bảng phải được viết lại, nó chỉ yêu cầu cập nhật siêu dữ liệu.

Vấn đề có thể xảy ra ở đâu, và tôi đặt cược cho bạn đô la để làm bánh rán rằng đó là vấn đề bạn đang gặp phải, nằm trong các ưu tiên khóa. Ai đó có khóa yếu, như khóa ACCESS SHARE, trên bàn đó và họ đang cắm trại vô thời hạn (có thể là kết nối giao dịch nhàn rỗi đã bị rò rỉ? Ai đó đã mở psql, bắt đầu truy vấn ở chế độ đọc lặp lại, và sau đó đi nghỉ?).

ADD COLUMN cố gắng lấy TIẾP CẬN ĐỘC QUYỀN mà nó cần, và nó xếp hàng sau khóa đầu tiên.

Bây giờ tất cả các yêu cầu khóa trong tương lai xếp hàng phía sau yêu cầu ACCESS EXCLUSIVE đang chờ.

Về mặt khái niệm, các yêu cầu khóa đến tương thích với khóa đã được cấp có thể vượt qua ACCESS EXCLUSIVE đang chờ và được cấp lần lượt, nhưng đó không phải là cách PostgreQuery thực hiện.

Bạn cần tìm quá trình giữ khóa yếu kéo dài.

Bạn có thể làm điều này bằng cách truy vấn bảng pg_locks.

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

Nếu bạn làm điều này trong khi mọi thứ bị khóa, bạn sẽ chỉ nhận được một câu trả lời (trừ khi có nhiều thủ phạm tồn tại lâu). Nếu bạn làm điều này sau khi bạn đã giết ADD COLUMN, thì bạn có thể thấy rất nhiều ổ khóa được cấp, nhưng nếu bạn lặp lại nó một vài lần thì sẽ có một hoặc một vài cái tồn tại mỗi lần.

Sau đó, bạn có thể lấy mã PID mà bạn nhận được từ pg_lock và truy vấn nó vào pg_stat_activity để xem người phạm tội đang làm gì:

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;

Vì vậy, nó đã chạy một truy vấn, bên trong một giao dịch, và sau đó không hoạt động mà không bao giờ đóng giao dịch. Bây giờ là 13:13, vì vậy họ đã nhàn rỗi trong 5 phút.


6
Câu trả lời này đã cứu mạng tôi
Mahendra

1
Tôi cũng đã cứu tôi, phần về lock prioritiesrất hay, vì tôi chưa đọc về điều đó ở những nơi khác, cảm ơn bạn!
Edson Horacio Junior
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.