快速解決PostgreSQL中的Permission denied問題
想開始學習SQL和Excel那本書,覺得自己親手去輸入才是正道。發現程式後續會用到視窗函式,可是我的mysql沒有視窗函式,這本書所提供的資料指令碼分別是MS SQL Sever和PostreSQL。
上午我先安裝的sql sever,可是由於比較大且在安裝時出現了一些小的問題(安裝緩慢,服務啟動不了)。無奈選擇了PostreSQL,體積小,安裝順利。
匯入資料比較特別,先建一個表,然後把同名txt匯入進去。一定要用unix方式的路徑。
copy這個語句先前在mysql上沒有遇到過。學習下。。。。
根據我的錯誤程式碼發現是許可權不夠,之前用mysql的時候並沒有注意到許可權這個問題。
哇,被許可權搞的真的頭皮發麻。中間的曲折過程就不表了,第一次瞭解到資料庫超級使用者這個概念,還有就是postresql的結構和
mysql也很不同。資料庫-模式-表。最後是用postres建立了一個超級使用者。但是發現還是報錯,拒絕訪問。我就想到可能是txt放在了C盤不能隨便訪問,所以我將data檔案放到了D盤,匯入成功。
成功了!今天一個下午算是折在這上面了,不過總算有收穫。瞭解了使用者,postresql中的copy。明天開始照著書做吧。
PS:(雖然這回的資料沒有中文)
補充:PostgreSQL的幾種常見問題和解決方法
1. 前言
1.1 概述
本文介紹了postgresql的幾種常見問題,並從現象出發,逐步排查問題,分析導致問題的原因並給出解決方案。
本文介紹的問題分為兩大類:一類是關於PostgreSQL無法啟動的問題,另一類是PostgreSQL啟動後,部分資料庫物件無法訪問的問題。
1.2 軟體環境
本文使用的 PostgreSQL 版本是 9.6。
1.3 一些約定術語
PostgreSQL安裝路徑:預設是 “D:\Program Files\PostgreSQL\9.6”
bin 資料夾:PostgreSQL安裝路徑下的bin資料夾。
data 資料夾:PostgreSQL安裝路徑下的data資料夾。
2. 問題和解決方法
2.1 PostgreSQL無法啟動
PostgreSQL 沒有正常啟動時,在 “服務”中再次啟動失敗。
2.1.1 端口占用
我們首先需要判斷是不是該服務的埠被佔用。PostgreSQL服務的預設埠是5432,那麼我們在命令列中執行如下命令
netstat -ano | find /i "5432"
如果發現了某個程序使用了5432這個埠,這說明是端口占用導致服務無法啟動:
這個程序的pid是2364,你想檢視它是什麼程序,可以執行:
tasklist | findstr "2364"
執行結果如下:
你可以在工作管理員-程序頁面中,或者通過下面的命令結束這個程序:
taskkill /f /pid 5432
小知識:
PostgreSQL 是多程序模型的資料庫。它在執行時,會啟動一個名為“pg_ctl”程序和若干個名為“postgres” 的程序。其中,程序pg_ctl是“祖先”程序,它表示資料庫處於執行狀態,佔用的記憶體很少;其他所有工作程序的名稱都是postgres。
在 Windows 作業系統上,如果 pg_ctl.exe 被異常關閉了,程序 postgres.exe 還會存在。資料庫執行埠仍然被佔用。會導致資料庫無法啟動。
2.1.2 檔案 postmaster.pid 殘留
進入 PostgreSQL的data 資料夾,檢視是否有殘留的檔案 postmaster.pid。正常情況下,PostgreSQL 在啟動時會建立這個檔案,其內容是 PostgreSQL 的主程序的 pid。如果它存在,則資料庫會認為自己已經啟動了,所以啟動失敗。
因此需要刪除這個檔案,再嘗試啟動資料庫。
2.1.3 could not open control file “global/pg_control”:Permission denied
如果埠沒有被佔用,那麼你可以用PostgreSQL原生的命令啟動它。
進入postgresql安裝路徑下的 bin 資料夾,在這裡開啟命令列,執行下面的命令:
.\pg_ctl start -D ..\data
如果程式報出如下錯誤:
ERROR: could not open control file “global/pg_control”: Permission denied
則說明當前作業系統使用者丟失了data資料夾及其內容的許可權。
下面是解決方法:
1. 首先,進入postgresql 的安裝路徑,右鍵data資料夾,依次點選屬性——安全——編輯,你能看到所有使用者或使用者組的許可權。
2. 確保System 和 Administrator 擁有“完全控制”許可權。Users 使用者組預設只擁有“讀取和執行”,“列出資料夾內容”和“讀取”3種許可權。當啟動資料庫提示“許可權不足”時,應再新增“修改”和 “寫入”。
3. 儲存並嘗試再次在bin 資料夾下執行:
.\pg_ctl start -D ..\data
觀察PostgreSQL資料庫能否啟動。
2.1.4 could not locate a valid checkpoint record
如果啟動資料庫時,提示“正在啟動伺服器程序”,且長時間無法啟動成功,如下圖所示,需要檢視資料庫執行日誌,它們位於data資料夾下的pg_log中的。
開啟問題發生時的資料庫執行日誌,檢視資訊。
如果日誌中出現類似下面黑體字的資訊,說明是PostgreSQL資料庫中的預寫式日誌(write ahead log,簡稱WAL,又稱事務日誌,簡稱xlog)損壞了:
LOG: could not open file "pg_xlog/0000000100000000000000E7" (log file 0,segment 231): No such file or directory LOG: invalid primary checkpoint record LOG: could not open file "pg_xlog/0000000100000000000000E7" (log file 0,segment 231): No such file or directory LOG: invalid secondary checkpoint record PANIC: could not locate a valid checkpoint record
解決方法如下:
進入bin 資料夾,在這裡開啟命令列,執行下面的命令:
.\pg_resetxlog.exe -f ..\data
在日誌重置後,再嘗試啟動資料庫。
2.1.5 failed to re-find parent key in index "227236" for split pages 370/371
有時,資料庫無法啟動時,我們檢視位於data資料夾下的pg_log中的資料庫執行日誌,會發現類似下面的資訊:
LOG: redo starts at 270/55E04AE8 LOG: could not open file pg_xlog/0000000100000270000000CC" (log file 624,segment 204): No such file or directory LOG: redo done at 270/CBFFE940 LOG: last completed transaction was at log time 2018-11-26 01:55:01.259996-02 FATAL: failed to re-find parent key in index "227236" for split pages 370/371 LOG: startup process (PID 5011) exited with exit code 1 LOG: aborting startup due to startup process failure
上面黑體字的資訊,同樣說明是PostgreSQL資料庫中的預寫式日誌檔案損壞了。
該問題的解決方法和2.1.3節的問題的解決方法相同。
2.1.6 無法找到來自源 PostgreSQL 的事件 ID 0 的描述。
如果上面的方法沒有解決問題,那麼我們需要進入事件管理器中檢視是否有錯誤日誌:
在事件檢視器-Windows日誌-應用程式中,檢視是否有如下錯誤日誌:
無法找到來自源 PostgreSQL 的事件 ID 0 的描述。本地計算機上未安裝引發此事件的元件,或者安裝已損壞。可以安裝或修復本地計算機上的元件。
如果出現了這樣的資訊,則說明PostgreSQL軟體已經損壞,需要重新安裝。不過,資料檔案不一定損壞了,因此如果上次備份至今,資料庫中產生過非常重要的資料(比如賬單資訊),你應該將data資料夾複製到另一個目錄,然後重新安裝平臺,並恢復data資料夾。
2.1.7 Could not read from file "pg_clog/000E" at offset 172032
還有一種不常見的情況。如果日誌中出現類似下面的資訊:
ERROR: could not access status of transaction 710708 DETAIL: Could not read from file "pg_clog/000E" at offset 172032: No error.
則表示位於data資料夾下pg_clog中的名為 000E 的提交日誌檔案丟失了。
解決方法如下:
在linux 作業系統中,執行下列命令:
dd if=/dev/zero of=/root/000E bs=256k count=1
或者在windows中安裝 dd,隨後執行:
dd if=/dev/zero of=D:\000E bs=256k count=1
然後將建立好的000E 檔案拷貝至data資料夾下的pg_clog 中。
2.2 資料庫啟動後,部分資料庫或表無法訪問
這種情況下,你需要進入 data資料夾下的pg_log資料夾,檢視問題發生時刻產生的執行日誌。
2.2.1 permission denied for relation tb_door
如果執行日誌出現類似下面的資訊,這說明是當前訪問使用者沒有表tb_door的某些許可權:
ERROR: permission denied for relation tb_door
如果你希望當前使用者(以myuser為例)擁有特定訪問許可權(以SELECT,INSERT,UPDATE ,DELETE為例),可以這樣解決:
首先,通過postgres使用者或擁有tb_door 相應訪問許可權即授予許可權的使用者登入資料庫;
執行如下命令,為使用者授予許可權:
grant SELECT,INSERT,UPDATE,DELETE on tb_door to myuser
2.2.2 must be owner of relation tb_door
如果執行日誌出現類似下面的資訊,這說明是當前使用者沒有表ac_door的所有權:
ERROR: must be owner of relation tb_door
你可以使用管理員postgres登入相應資料庫,手動執行下面命令將tb_door的屬主你希望的使用者,以myuser為例:
Alter table tb_door owner to myuser;
2.2.3 invalid page header in block 120 of relation base/272816/309624
如果日誌中出現類似下面的資訊:
ERROR: invalid page header in block 120 of relation base/272816/309624
則表示資料表文件損壞。這通常是由於異常斷電或誤操作導致的。這裡“272816”是發生問題的資料庫的物件id(oid), “309624”表示發生問題的表的檔案結點(filenode)
如果發生損壞的表以及損壞的頁面數量較少,我們可以以犧牲部分資料的代價恢復整體;如果損壞的表數量過多,或者損失的資料非常重要,就需要從備份中恢復資料了。
當發生損壞的表以及損壞的頁面數量較少時,解決方法如下:
確定發生問題的資料庫。連線任意資料庫,執行下面的sql語句:
select datname from pg_database where oid = 272816;
查詢結果如下:
testdb
這表示發生問題的資料庫名是testdb
2. 查詢損壞的資料庫物件。連線發生問題的資料庫,執行下面的sql語句:
select relname,relkind from pg_class where relfilenode = 309624
如果查詢結果中 relkind = r,表示損壞的是表。
例如:
tb_door,r
relname = tb_door這表示損壞的表是tb_door。
如果查詢結果中relkind = i,表示損壞的是一個索引。
例如:
dept_number_index,i
或者:
tb_dept_pkey,i
需要注意,損壞的可能是普通索引,也可能是主鍵或唯一鍵。如果索引的名稱中有“_pkey”等很可能屬於主鍵,而名稱中含有 “_key”則很可能屬於唯一鍵。
還需要格外注意一點,表/索引可修復的前提條件是損壞的表是應用程式建立的表/索引,而不是PostgreSQL的系統表和建立在其上的索引。如果系統表/建立在其上的索引發生損壞,則需要從備份中恢復資料庫。判斷一個表是否是系統表,最簡單的方法是:如果表名是“pg_”開頭的,則說明它是系統表。
小知識
pgclass.relkind 的值有下面幾種:
r: 表示ordinary table(普通表);
i: 表示index(索引);
S: 表示sequence(序列);
V: 表示view(檢視);
m: 表示materialized view(物化檢視);
c: 表示composite type(複合型別);
t: 表示TOAST table(TOAST 表);
f: 表示foreign table(外部表)
3. 修復損壞的資料庫物件。連線發生損壞的資料庫,執行修復命令。
如果損壞的是表,以tb_door為例,則依次執行下列命令即可完成修復:
set zero_damaged_pages = on; vacuum full tb_door; reindex table tb_door;
如果損壞的是普通索引,以dept_number_index為例, 則依次執行:
set zero_damaged_pages = on; reindex index dept_number_index;
如果損壞的是主鍵或唯一鍵,則首先需要找到它所在的表,以tb_dept_pkey為例:
Select tablename,indexname from pg_indexes where indexname = ‘tb_dept_pkey';
查詢結果:
tb_dept,tb_dept_pkey
然後獲取索引的定義:
select pg_get_constraintdef((select oid from pg_constraint where conname = ' tb_dept_pkey '));
查詢結果:
PRIMARY KEY (dept_id)
然後重新建立這個約束:
Alter table drop constriant tb_dept_pkey; Alter table add constraint tb_dept_pkey PRIMARY KEY (dept_id);
2.2.4 could not read block 190 in file "base/272816/309624"
該問題的解決方法與2.2.2 節的問題完全相同。
2.2.5 could not open file "base/272816/379923": No such file or directory
如果日誌中出現類似下面的資訊:
2019-01-21 14:28:03 HKT ERROR: could not open file "base/272816/379923": No such file or directory
則說明,oid為272816的資料庫中,oid為379923的表對應的檔案被刪除了。
解決方法如下:
1. 首先判斷是哪一個資料庫中發生了此問題。連線任意資料庫,執行如下sql:
select datname from pg_database where oid = 272816
查詢結果如下:
testdb
2. 從備份中恢復該資料庫。
2.3 資料庫啟動後,部分資料庫或表無法訪問
2.3.1 No buffer space available
有時,在服務管理器中,PostgreSQL 顯示為 正在執行狀態,但是使用客戶端連線使,提示“could not connect to server: No buffer space available”,在postgresql執行日誌中,也能看到類似日誌。
解決方法如下:
首先,在服務管理器中關閉 PostgreSQL 服務。
嘗試用 PostgreSQL 自身的命令啟動它。進入postgresql安裝路徑下的 bin 資料夾,在這裡開啟命令列,執行下面的命令:
.\pg_ctl start -D ..\data
3. 觀察提示資訊。如果提示PostgreSQL啟動成功,則用客戶端連線資料庫;如果啟動不成功,則參考 2.1 章的內容。
4. 如果仍然有這樣的錯誤提示,那說明很可能是記憶體不足。你需要在作業系統中檢視記憶體,如果發現可用記憶體較少,那你需要觀察是否有服務記憶體異常過高,並處理它。在 Windows 上 有一種特殊的情況,各種服務起來正常,但記憶體很少,這是因為 windows Socket 連線關閉後,記憶體不釋放。對於windows 2008,解決方法是打 windows補丁 KB2577795。
2.3.2 no pg_hba.conf entry for host
如果日誌中出現類似下面的資訊:
FATAL: no pg_hba.conf entry for host "192.168.0.123",user "testuser",database "testdb"
則表示資料庫伺服器沒有允許來自地址192.168.0.123的 testuser 使用者訪問資料庫testdb。
解決的方法如下:
檢查 data 目錄中的配置檔案 postgresql.conf 中的引數 listen_addresses,把它的值改為 '*',或者包含客戶端的IP。
修改data 目錄中的訪問許可權配置檔案 pg_hba.conf。如果你希望所有地址的所有使用者可以訪問此伺服器中的全部資料庫,可以新增下面這一行:
host all all 0.0.0.0/0 md5
如果你只希望192.168.0.123 上的使用者可以訪問此資料庫,則新增:
host all all 192.168.0.123/32 md5
或者你僅僅希望192.168.0.123 上的 testuser 使用者可以訪問此資料庫,則新增:
host testuser all 192.168.0.123/32 md5
重啟資料庫即可。
小知識:
pg_hba.conf 是 postgresql 服務端的訪問許可權控制檔案,控制來自哪裡的什麼使用者,以什麼建立方式連線,以什麼方法認證,訪問哪一個資料庫。每行是一個訪問控制條目,內容的示例如下:
host all all 127.0.0.1/32 md5
每列的含義如下:
第一列表示訪問域的型別,其值有local,host,hostssl,hostnossl。一般選擇 host,表示使用 TCP/IP 建立的連線。
第二列表示允許訪問的資料庫使用者,“all” 表示所有使用者可以訪問。
第三列表示允許被訪問的資料庫名,“all” 表示所有資料庫都允許被訪問。
第四列表示允許訪問的ip地址,127.0.0.1/32表示本地IP地址,192.168.0.123/32 表示地址192.168.0.123,192.168.0.0/24表示子網192.168.0.0 ~ 192.168.0.255,0.0.0.0/0表示任何IP地址。
第五列是認證的方式。“md5” 表示MD5密碼認證,trust表示無密碼認證。
2.3.3 No connection could be made because the target machine actively refused it.
如果日誌中出現類似下面的資訊:
LOG: could not receive data from client: No connection could be made because the target machine actively refused it.
則表示有一些因素使資料庫伺服器拒絕了客戶端的連線。
解決的思路如下:
首先檢查平臺有沒有單點登入。如果有,關閉。
檢查有沒有安裝防火牆,如果有,允許5432埠連線。
檢查 data 目錄中的配置檔案 postgresql.conf 中的引數 listen_addresses,把它的值改為 '*',或者包含客戶端的IP。
修改data 目錄中的訪問許可權配置檔案 pg_hba.conf。如果你希望所有地址的所有使用者可以訪問此伺服器中的全部資料庫,可以新增下面這一行:
host all all 0.0.0.0/0 md5
如果你只希望192.168.0.123 上的使用者可以訪問此資料庫,則新增:
host all all 192.168.0.123/32 md5
5. 重啟資料庫,觀察能否訪問。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。如有錯誤或未考慮完全的地方,望不吝賜教。