表重写简介
在实践状况中,引宣布重写的 DDL 命令十分风险,它们或者会造成不确定的停机时期,在某些状况下或者须要 ~ 2 倍的磁盘空间。
通常,引宣布重写的 DDL 命令,换句话说,也就是造成 relfilenode (表文件号)更改的 DDL 命令,通常会阻塞并发的上班负载。
简明引见一下背景信息,PostgreSQL 中的每个惯例表都将数据存储在一个或多个文件中,这些文件在系统表中经常使用一个 relfilenode 启动援用。审核成性能否会创立/援用另一个正本(文件)的一种简双方法是,审核 relfilenode 能否出现了更改。TRUNCATE 在这里较为不凡,依照设计,它会肃清表数据,因此虽然 relfilenode 也会出现更改,但总的来说,它显然不会消耗凑近 2 倍的磁盘空间。
哪些 DDL 命令会引宣布重写?
下表显示了哪些 DDL 会引宣布重写。此表可以协助您,为允许的一切 PostgreSQL 版本,做出一些与并发/磁盘经常使用关系的决策。
表重写场景 |
v10 |
v11 |
v12 |
v13 |
v14 |
v15 |
v16 |
v17 |
ALTER TABLE ADD COLUMN INTEGER |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN INTEGER NULL |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN INTEGER NOT NULL |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN INTEGER DEFAULT 100000 |
是 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN INTEGER DEFAULT 100000 NULL |
是 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN INTEGER DEFAULT 100000 NOT NULL |
是 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN TEXT COLLATE german |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN TEXT COLLATE german NULL |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN TEXT COLLATE german NOT NULL |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN TEXT COLLATE german DEFAULT 'ß' |
是 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN TEXT COLLATE german DEFAULT 'ß' NULL |
是 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ADD COLUMN TEXT COLLATE german DEFAULT 'ß' NOT NULL |
是 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE DROP COLUMN |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN TYPE VARCHAR(1000) -- 二进制兼容 (Varchar(M) -> Varchar(N)) |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN TYPE TEXT -- 二进制兼容 (Varchar -> Text) |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN TYPE TEXT -- 二进制不兼容 (Int -> Text) |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
ALTER TABLE ALTER COLUMN TYPE BIGINT -- 很经常出现的场景(例如 Int -> Bigint) |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
ALTER TABLE ALTER COLUMN TYPE TEXT COLLATE german; -- 之前列类型为 Int |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
ALTER TABLE ALTER COLUMN TYPE TEXT COLLATE german; -- 之前列类型为 Text |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN TYPE TEXT COLLATE german; -- 之前列类型为 Varchar() |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET DEFAULT 10000 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN DROP DEFAULT |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET NOT NULL |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN DROP NOT NULL |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN ADD GENERATED ALWAYS AS IDENTITY |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN DROP IDENTITY |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET STATISTICS -1 -- 从非自动值更改 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET STATISTICS 1000 -- 从非自动值更改 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET STATISTICS 1000 -- 从自动值更改 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET (n_distinct=100) |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN RESET (n_distinct) |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET STORAGE MAIN |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET STORAGE PLAIN |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET STORAGE EXTERNAL |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE ALTER COLUMN SET STORAGE EXTENDED |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE CLUSTER ON; |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE SET WITHOUT CLUSTER |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE SET WITH OIDS |
是 |
是 |
||||||
ALTER TABLE SET WITHOUT OIDS |
是 |
是 |
是[2] |
是[2] |
是[2] |
是[2] |
是[2] |
是[2] |
ALTER TABLE SET TABLESPACE tmp_tblspc |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
ALTER TABLE SET LOGGED |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
ALTER TABLE SET UNLOGGED |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
ALTER TABLE SET (FILLFACTOR=10) |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE RESET (FILLFACTOR) |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER TABLE INHERIT |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
ALTER INDEX set tablespace tmp_tblspc |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
DELETE FROM |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
CLUSTER |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
COMMENT ON TABLE IS 'testing' |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
否 |
TRUNCATE TABLE |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
VACUUM FULL |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
[1] 在此版本中该 SQL 已废除。
[2] 为 WITHOUT OIDs 标志,纯正是出于审慎思索。重写仅在 WITH OIDs 的表启动主版本更新时期出现。
制止引宣布重写的 DDL 命令
PostgreSQL 允许table_rewrite事情。table_rewrite事情在表被ALTER TABLE和ALTER TYPE命令的某些举措重写之前出现。虽然其余控制语句(例如CLUSTER和VACUUM)也会引发重写表,然而它们不会触发table_rewrite事情。
得益于table_rewrite事情的存在,咱们可以成功一种表重写战略,间接制止这些 DDL 命令。上方是成功这种战略的一个例子。
CREATE OR REPLACE FUNCTION forbid_table_rewrites()RETURNS event_triggerAS $$BEGINRAISE EXCEPTION 'command % prohibited', tg_tag;END;$$ LANGUAGE plpgsql;CREATE EVENT TRIGGER forbid_rewritesON table_rewriteEXECUTE FUNCTION forbid_table_rewrites();ALTER TABLE foo ALTER COLUMN id TYPE BIGINT;ERROR:command ALTER TABLE prohibitedCONTEXT:PL/pgSQL function forbid_table_rewrites()line3 at RAISE