1. 程式人生 > >PostgreSQL使用建議(非常實用)

PostgreSQL使用建議(非常實用)

一、命名規範

1. DB object: database, schema, table, view, index, function, trigger等名稱
(1) 建議使用小寫字母、數字、下劃線的組合
(2) 建議不使用雙引號即"包圍,除非必須包含大寫字母或空格等特殊字元
(3) 長度不能超過63個字元
(4) 禁止使用 
SQL 關鍵字,例如 type, order 

2. table能包含的column數目,根據欄位型別的不同,數目在 250 到 1600 之間

3. 臨時或備份的DB object:table,view ,建議加上日期,table_xxx_20150826

4. index命名規則為

表名_列名_idx,student_name_idx, 建議不顯式給出index name,使用DBMS系統預設給出的index name, create index ON student (name);則預設給出student_name_idx

二、Column設計

1. 建議能用varchar(N) 就不用char(N),以利於節省儲存空間

2. 建議能用varchar(N) 就不用text,varchar

3. 建議使用default NULL,而不用default '',以節省儲存空間,

4. 建議使用ip4,ip4r,ip6,ip6r,ipaddress,iprange 來儲存

IP,IP範圍;使用macaddr來儲存MAC (Media Access Control) address

5. 建議使用timestamp with time zone(timestamptz),而不用timestamp without time zone,避免時間函式在對於不同時區的時間點返回值不同,也為業務國際化掃清障礙

6. 建議使用NUMERIC(precision, scale)來儲存貨幣金額和其它要求精確計算的數值而不建議使用real, double precision

7. 建議使用hstore 來儲存非結構化,key-value 鍵值型,對數不定的資料

8. 建議使用ltree 

來儲存 Top.中國.北京.天安門 這種樹狀層次結構 資料

9. 建議使用json 來儲存JSON (JavaScript Object Notation) data

11. 建議使用如下range型別代替字串或多列來實現範圍的儲存

三、Constraints設計

1. 建議每個table都有主鍵;

2. 建議不要用有業務含義的名稱作為主鍵,比如身份證或者國家名稱,儘管其是unique

3. 建議主鍵的一步到位的寫法:id serial primary key id bigserial primary key

四、Index設計

1. PostgreSQL 提供的index型別: B-tree, Hash, GiST (Generalized Search Tree), SP-GiST (space-partitioned GiST) and GIN (Generalized Inverted Index),目前不建議使用Hash, SP-GiST

2. 建議create 或 drop index ,加 CONCURRENTLY引數,這是個好習慣,達到與寫入資料併發的效果

3. 建議對於頻繁update, delete的包含於index 定義中的columntable, create index CONCURRENTLY , drop index CONCURRENTLY 的方式進行維護其對應index

4. 建議用unique index 代替unique constraints,便於後續維護

5. 建議不要建過多index,一般不要超過6個,核心table(產品,訂單)可適當增加index個數

五、關於NULL

1. NULL 的判斷:IS NULL IS NOT NULL

2. 注意boolean 型別取值 truefalse, NULL

3. 小心NOT IN 集合中帶有NULL元素

postgres=# SELECT * FROM (VALUES(1),(2)) v(a) ; 
 a
 --- 
 1 
 2
 (2 rows)  
postgres=# select 1 NOT IN (1, NULL); 
 ?column?
 ---------- 
 f
 (1 row)  
postgres=# select 2 NOT IN (1, NULL); 
 ?column?
 ---------- 
 
(1 row) 
postgres=# SELECT * FROM (VALUES(1),(2)) v(a) WHERE a NOT IN (1, NULL); 
 a
 ---
(0 rows)

可見,出現這種情況的根本原因在於SELECT只返回WHERE中判斷條件結果為true的資料

4. 建議對字串型NULL值處理後,進行 || 操作

postgres=# select NULL||'PostgreSQL'; 
 ?column?
 ---------- 
 
 (1 row) 
postgres=# select coalesce(NULL,'')||'PostgreSQL';  
 ?column?
 ------------ 
 PostgreSQL
 (1 row)

5. 建議對hstore 型別進行處理後,進行 || 操作,避免被NULL吃掉

postgres=# select  NULL::hstore || ('key=>value') ; 
 ?column?
 ---------- 
 
 (1 row) 
postgres=# select  coalesce(NULL::hstore, hstore(array[]::varchar[])) || ('key=>value') ;
?column?
----------------
 "key"=>"value"
 (1 row) 
postgres=# select  coalesce(NULL::hstore,''::hstore) || ('key=>value') ;    
 ?column?    
 ----------------
  "key"=>"value"
  (1 row)

六、其他注意事項

1. 建議對DB object 尤其是COLUMN COMMENT,便於後續維護

2. 建議非必須時避免select *,只取所需欄位,以減少網路頻寬消耗,避免表結構變更對程式的影響

3. 建議update 時儘量做 <> 判斷,比如update table_a set column_b = c where column_b <> c

4. 建議將單個事務的多條SQL操作,分解、拆分,或者不放在一個事務裡,讓每個事務的粒度儘可能小,儘量lock少的資源,避免lock dead lock的產生

5. 建議向大sizetableadd column時,將 alter table t add column col datatype not null default xxx;分解為如下,避免填充default值導致的過長時間鎖表

alter table t add column col datatype ; 
alter table t alter column col set default xxx; 
update t set column = default where id = 1; 
.................. 
update t set column = default where id = N; 
------此處,可以用先進的\watch來刷------即 
update table t  set column= DEFAULT where id in ( select id from t where column is null limit 1000 ) ; \watch 3 
alter table t alter column col set not null;

6. 建議執行DDL,比如CRAETE,DROP,ALTER 不要顯式的開transaction, 因為加lockmode非常高,極易產生deadlock

8. 建議發給PostgrSQL DBA review 及 執行的SQL,無論是使用pgadmin這種圖形化工具,還是pg_dump 這種命令列工具生成的SQL,都去掉註釋(--之後的部分),雙引號"及alter owner等冗餘或不應該帶到線上生產的dev/beta DB中的資訊