閱讀714 返回首頁    go 阿裏雲 go 技術社區[雲棲]


如何優雅的ALTER被引用的TABLE

標簽

PostgreSQL , 視圖 , 表 , alter table , 修改字段屬性


背景

在修改數據庫表字段的長度時,數據庫提供了alter table的語法進行修改。

但是被修改的字段如果有其他引用(例如視圖)時,必須先將引用的對象刪除,再修改對應的字段。

例子如下

測試表  
postgres=# create table test_t (id int, info text, crt_time timestamp, c1 varchar(10));  
CREATE TABLE  
  
被修改字段上建立索引  
postgres=# create index idx_test_t on test_t(c1);  
CREATE INDEX  
  
被修改字段上建立視圖  
postgres=# create view v_test_t as select id,c1 from test_t;  
CREATE VIEW  
  
修改字段的長度報錯  
postgres=# alter table test_t alter column c1 type varchar(32);  
ERROR:  cannot alter type of a column used by a view or rule  
DETAIL:  rule _RETURN on view v_test_t depends on column "c1"  

優雅的修改被視圖引用的表字段

PostgreSQL支持將DDL語句封裝在事務中處理,所以從刪除依賴,到修改字段,再到重建依賴,都可以封裝在一個事務中完成。

注意

1. DDL是需要對表加排它鎖的,排它鎖與所有其他鎖衝突,因此建議在事務開始時設置鎖超時參數,避免問題。

2. 如果修改字段涉及到rewrite table(例如int改到text),那麼表很大時間會很久。如果需要很久,意味著需要長時間持有排它鎖(堵塞也是比較嚴重的)。

例子

begin;  -- 開始事務  
  
set local lock_timeout = '1s';  -- 設置鎖超時  
  
drop view v_test_t;  -- 刪除依賴視圖  
  
alter table test_t alter column c1 type varchar(32);  -- 修改字段長度  
  
create view v_test_t as select id,c1 from test_t;  -- 創建視圖  
  
end;  -- 結束事務  

hack PostgreSQL pg_attribute元數據的修改方法

PostgreSQL的定義都記錄在元數據中,所以某些操作,可以直接修改元數據來實現。比如從numeric低精度修改到高精度,從字符串短長度修改到長長度。

注意

不建議這麼做,直接修改元數據存在隱患,甚至可能對數據庫造成不可修複的傷害。

例子

首先要查看將要修改的C1字段的pg_attribute元信息

視圖、索引、表 在pg_attribute中都有對應的元信息,如下  
  
postgres=# select attrelid::regclass,* from pg_attribute where attname='c1';  
  attrelid  | attrelid | attname | atttypid | attstattarget | attlen | attnum | attndims | attcacheoff | atttypmod | attbyval | attstorage | attalign | attnotnull | atthasdef | attidentity | attisdropped | attislocal | attinhcount | attcollation | attacl | attoptions | attfdwoptions   
------------+----------+---------+----------+---------------+--------+--------+----------+-------------+-----------+----------+------------+----------+------------+-----------+-------------+--------------+------------+  
  
 test_t     |    21988 | c1      |     1043 |            -1 |     -1 |      4 |        0 |          -1 |        36 | f        | x          | i        | f          | f         |             | f            | t          |           0 |          100 |        |            |   
 v_test_t   |    21998 | c1      |     1043 |            -1 |     -1 |      2 |        0 |          -1 |        36 | f        | x          | i        | f          | f         |             | f            | t          |           0 |          100 |        |            |   
 idx_test_t |    22002 | c1      |     1043 |            -1 |     -1 |      1 |        0 |          -1 |        36 | f        | x          | i        | f          | f         |             | f            | t          |           0 |          100 |        |            |   
(6 rows)  

在修改時,需要將這三個atttypmod一起修改掉。

變長字段的長度為4字節頭+實際長度,所以36表示可以存儲32個字符。

修改為varchar(64)這樣操作

postgres=# update pg_attribute set atttypmod=68 where attname='c1' and attrelid in (21988,21998,22002);  
UPDATE 3  

更新後,可以看到結構發生了變化.

postgres=# \d+ test_t  
                                              Table "public.test_t"  
  Column  |            Type             | Collation | Nullable | Default | Storage  | Stats target | Description   
----------+-----------------------------+-----------+----------+---------+----------+--------------+-------------  
 id       | integer                     |           |          |         | plain    |              |   
 info     | text                        |           |          |         | extended |              |   
 crt_time | timestamp without time zone |           |          |         | plain    |              |   
 c1       | character varying(64)       |           |          |         | extended |              |   
Indexes:  
    "idx_test_t" btree (c1)  
  
postgres=# \d+ v_test_t  
                                  View "public.v_test_t"  
 Column |         Type          | Collation | Nullable | Default | Storage  | Description   
--------+-----------------------+-----------+----------+---------+----------+-------------  
 id     | integer               |           |          |         | plain    |   
 c1     | character varying(64) |           |          |         | extended |   
View definition:  
 SELECT test_t.id,  
    test_t.c1  
   FROM test_t;  
  
postgres=# \d+ idx_test_t   
               Index "public.idx_test_t"  
 Column |         Type          | Definition | Storage    
--------+-----------------------+------------+----------  
 c1     | character varying(64) | c1         | extended  
btree, for table "public.test_t"  

參考

《如何比較PostgreSQL表的定義》

《PostgreSQL 9.0 modify pg_attribute.atttypmod extend variable char length avoid rewrite table》

《PostgreSQL WHY modify numeric scale must rewrite table》

《PostgreSQL How can i decode the NUMERIC precision and scale in pg_attribute.atttypmod》

最後更新:2017-05-03 21:49:06

  上一篇:go 企業級互聯網架構 Aliware 全新升級
  下一篇:go mina 框架知識點部分整理