База даних "заморожена" на 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.

Цей запис у блозі містить підсумок, який передбачає, що додавання стовпця може бути операцією в Інтернеті, якщо стовпчик є нульовим і не має значення за замовчуванням або унікального обмеження, хоча це означає, що заява, яку ви заявляєте, мала виконуватись без блокування (як поштові повідомлення IIRC за замовчуванням стовпці мають значення NULLable, якщо ви прямо не вказали інше). Ви виконували якісь інші операції після стовпця "Додати"? Можливо, створити на ньому індекс (який би замовчував блокування запису на столі)?

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


35

Команда, яку ви хочете виконати, робить блокування ACCESS EXCLUSIVE на столі, перешкоджаючи всьому іншому доступу до цієї таблиці. Але тривалість цього блокування повинна становити лише кілька мілісекунд, оскільки для додавання стовпця, такого як той, який ви хочете додати, не потрібно перезаписувати таблицю, вона просто потребує оновлення метаданих.

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

ADD COLUMN намагається взяти ЕКСКЛЮЗИВНИЙ ДОСТУП, який потрібен, і він стоїть в черзі за першим замком.

Тепер усі майбутні запити блокування стоять за черговим запитом 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.