ALTER TABLE上のデータベース「凍結」


15

私たちの本番環境は、今朝、テーブルを変更し、実際に列を追加するときにしばらく凍結しました*。

問題のある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();  

CONSTRAINTS、TRIGGERS、または他の何かを無効にする必要がありますか?

おそらくDBチューニング?

さらに分析するには、他に何を提供する必要がありますか?

バージョン:gcc(Debian 4.9.2-10)4.9.2、64ビットでコンパイルされたx86_64-unknown-linux-gnu上のPostgreSQL 9.4.5


DDLステートメントが実行されている限り、テーブルはロックされており、アクセスできません。あなたがそれについてできることは何もありません。
-a_horse_with_no_name

まあ、期待したほど素敵ではありませんが、絶対に理解できます;)
ゴンサロバスケス

回答:


8

DDL操作は通常、操作対象のオブジェクトをロックするため、計画されたメンテナンスウィンドウの外で実行しないでください(ユーザーが中断を予期している場合、またはシステムが計画された時間まで完全にオフラインになる場合)-できることはありませんこれについて簡単に1

一部の操作は書き込みロックのみを保持するため、アプリケーションは、影響を受けるオブジェクトのみを読み取るリクエストを処理し続けることができます。

ドキュメントは、DDL操作によって保持される可能性のあるロックを一覧表示するのに非常に適しているようです。

このブログエントリには、列がNULL可能であり、デフォルト値または一意の制約がない場合、列の追加がオンライン操作になる可能性があることを示唆する要約がありますが、それはあなたが述べるステートメントがロックなしで実行されるべきであることを意味します(IIRC postgresとして)特に明記しない限り、列はデフォルトでNULL可能になります)。列の追加後に他の操作を実行しましたか?おそらくインデックスを作成します(デフォルトでテーブルの書き込みロックを取得します)?

1 レプリケーション/クラスタリング/ミラーリングの配置によっては、ミラーを更新し(変更中に更新を一時停止してから再生する)、各コピーが更新されるまでそのコピーをライブコピーとして使用するように切り替えることができるため、ダウンタイムは、DDL操作中に行われた変更の再生にかかる時間に制限されます。ただし、そのようなライブ操作にはリスクがないわけではないので、絶対にできない場合を除き、代わりに適切なメンテナンスウィンドウを配置して、構造的な更新を実行および検証することをお勧めします。


35

実行するコマンドは、テーブルに対するACCESS EXCLUSIVEロックを取得し、そのテーブルへの他のすべてのアクセスを防止します。ただし、このロックの期間は数ミリ秒である必要があります。追加する列のような列を追加する場合、テーブルを書き換える必要はなく、メタデータを更新するだけです。

問題が発生する可能性があり、ドーナツにあなたが見ている問題であると私はあなたにドルを賭けます、ロックの優先順位です。誰かがそのテーブルにACCESS SHAREロックのような弱いロックを持ち、それを無期限にキャンプしています(おそらく、トランザクションでアイドル状態の接続がリークされていますか?psqlを開いた人は、繰り返し可能な読み取りモードでクエリを開始しました、そして休暇に行った?)。

ADD COLUMNは、必要なACCESS EXCLUSIVEを取得しようとし、最初のロックの後ろにキューイングします。

これで、今後のロック要求はすべて、待機中のACCESS EXCLUSIVE要求の後ろにキューイングされます。

概念的には、すでに許可されたロックと互換性のある着信ロック要求は、待機中のACCESS EXCLUSIVEを飛び越えて順番を無視して許可される可能性がありますが、PostgreSQLの方法ではありません。

長期間存続する弱いロックを保持しているプロセスを見つける必要があります。

これを行うには、pg_locksテーブルをクエリします。

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

すべてがロックされているときにこれを行うと、1つの回答しか得られません(長命の犯人が複数いない場合)。すでにADD COLUMNを削除した後にこれを行うと、多くの許可されたロックが表示される場合がありますが、それを数回繰り返すと、そのたびに1つまたはいくつかのロックが維持されます。

次に、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分間アイドル状態になっています。


6
この答えは私の命を救った
マヘンドラ

1
私も保存しました、についての部分lock prioritiesは非常に良かったです、私が他の場所でそれについて読んでいなかったので、ありがとう!
エドソン・ホラシオジュニア
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.