表重写简介
在实际情况中,引发表重写的 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
本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载者并注明出处:https://jmbhsh.com/yulebagua/35678.html