爲PostgreSQL數據庫中沒有主鍵的表增長主鍵

PostgreSQL數據庫測試環境中有多張表沒有添加主鍵約束,只有一個serial的自增字段。如今須要把那些沒有主鍵的表都加上,serial類型的字段爲id 。html

首先是怎麼找到PostgreSQL數據庫中哪些表沒有主鍵?咱們看下pg_class這個表,裏面有個relhaspkey字段,若是爲t說明有主鍵,f即沒有主鍵。例以下面這個sql 。sql

SELECT n.nspname AS "Schema",c.relname AS "Table Name",c.relhaspkey AS "Has PK" 
FROM
 pg_catalog.pg_class c
JOIN
 pg_namespace n
ON (
 c.relnamespace = n.oid
 AND n.nspname NOT IN ('information_schema', 'pg_catalog')
 AND c.relkind='r'
)
WHERE c.relhaspkey = 'f'
ORDER BY c.relhaspkey, c.relname
;

而後就是對這些表增長主鍵約束。刪除和添加主鍵的sql以下所示:數據庫

alter table server drop constraint server_pkey ;
alter table server add primary key (id) ;

主鍵添加完成以後能夠經過\d查看。bash

zhangnq=# \d server
 Table "public.server"
 Column | Type | Modifiers 
--------+---------------+------------------------------------------------------
 id | integer | not null default nextval('server_int_seq'::regclass)
 ip | character(50) | 
Indexes:
 "server_pkey" PRIMARY KEY, btree (id)

最後就是把這個思路寫到腳本里面,運行腳本批量添加。腳本里面把執行失敗的表都放在error.log文件中。併發

腳本:高併發

#!/bin/bash
export PATH=/opt/PostgreSQL/93/bin:$PATH
export PGDATA=/data/pgsql
export PGHOME=/opt/PostgreSQL/93
export PGPORT=5432
dbname=$1
if [ ! $dbname ];then
 echo "Please enter the database name."
 exit 1
fi
psql -c "\dt" -d $dbname >/dev/null
if [ $? -ne 0 ];then
 exit 1
fi
error_log="error.log"
echo "">$error_log
sql=`cat << EOF
SELECT n.nspname AS "Schema",c.relname AS "Table Name"
FROM
 pg_catalog.pg_class c
JOIN
 pg_namespace n
ON (
 c.relnamespace = n.oid
 AND n.nspname NOT IN ('information_schema', 'pg_catalog')
 AND c.relkind='r'
)
WHERE c.relhaspkey = 'f'
ORDER BY c.relhaspkey, c.relname
;
EOF`
schemas=`psql -t -A -c "$sql" -d $dbname |cut -d "|" -f 1`
tables=`psql -t -A -c "$sql" -d $dbname |cut -d "|" -f 1`
for res in `psql -t -A -c "$sql" -d $dbname`
do
 schema=`echo $res|cut -d "|" -f 1`
 table=`echo $res|cut -d "|" -f 2`
 tablename=`echo "$schema.$table"`
 psql -e -c "alter table $tablename add primary key (id) " -d $dbname
 if [ $? -ne 0 ];then
 echo "$dbname : Add primary key to $tablename error." >>$error_log
 fi
done

說下碰到的的問題,在測試的時候發現若是把主鍵drop掉以後pg_class.relhaspkey值仍是爲t,可是用\d查看確實沒有主鍵了。解決的辦法是手動vacuum這個表,即vacuum server 。post

zhangnq=# select relname,relhaspkey from pg_class where relname='server' ;
 relname | relhaspkey 
---------+------------
 server | t
(1 row)
zhangnq=# alter table server drop constraint server_pkey ;
ALTER TABLE
zhangnq=# select relname,relhaspkey from pg_class where relname='server' ;
 relname | relhaspkey 
---------+------------
 server | t
(1 row)
zhangnq=# vacuum server ;
VACUUM
zhangnq=# select relname,relhaspkey from pg_class where relname='server' ;
 relname | relhaspkey 
---------+------------
 server | f
(1 row)
zhangnq=# alter table server add primary key (id) ;
ALTER TABLE
zhangnq=# select relname,relhaspkey from pg_class where relname='server' ;
 relname | relhaspkey 
---------+------------
 server | t
(1 row)

查看pg_class的說明後發現原來pg_class只有在狀態由false變成ture的時候會自動修改。這麼設計能夠提升併發性。測試

Several of the Boolean flags in pg_class are maintained lazily: they are guaranteed to be true if that's the correct state, but may not be reset to false immediately when the condition is no longer true. For example, relhasindex is set by CREATE INDEX, but it is never cleared by DROP INDEX. Instead, VACUUM clears relhasindex if it finds the table has no indexes. This arrangement avoids race conditions and improves concurrency.

 

參考連接:spa

http://www.postgresql.org/message-id/1395116664140-5796526.post@n5.nabble.com.net

原文地址:http://www.sijitao.net/2026.html

相關文章
相關標籤/搜索