一個 PostgreSQL 資料庫叢集包含一個或多個命名的資料庫。角色和其他一些物件型別在整個叢集中共享。客戶端連線到伺服器時,只能訪問單個數據庫中的資料,即連線請求中指定的那個資料庫。
叢集的使用者不一定有權訪問叢集中的每個資料庫。角色名稱的共享意味著在同一個叢集的兩個資料庫中不能存在兩個同名的角色,例如 joe
;但系統可以配置為允許 joe
僅訪問其中一些資料庫。
一個數據庫包含一個或多個命名的 模式,這些模式又包含表。模式還包含其他型別的命名物件,包括資料型別、函式和運算子。在一個模式中,相同型別的兩個物件不能有相同的名稱。此外,表、序列、索引、檢視、物化檢視和外部表共享同一個名稱空間,因此,例如,如果一個索引和表在同一個模式中,它們必須有不同的名稱。不同的模式可以使用相同的物件名稱而不會發生衝突;例如,schema1
和 myschema
都可以包含名為 mytable
的表。與資料庫不同,模式不是嚴格分隔的:如果使用者有許可權訪問,他們可以訪問他們所連線的資料庫中任何模式中的物件。
使用模式有幾個原因:
允許許多使用者使用同一個資料庫而不相互干擾。
將資料庫物件組織成邏輯組,使其更易於管理。
第三方應用程式可以放入獨立的模式中,以免與其它物件的名稱衝突。
模式類似於作業系統層面的目錄,不同之處在於模式不能巢狀。
要建立模式,請使用 CREATE SCHEMA 命令。為模式指定您選擇的名稱。例如:
CREATE SCHEMA myschema;
要建立或訪問模式中的物件,請使用由模式名稱和表名稱(用點分隔)組成的 限定名稱。
schema
.
table
這在期望表名出現的地方都可用,包括修改表的命令以及後續章節中討論的資料訪問命令。(為簡潔起見,我們將只討論表,但同樣的概念也適用於其他型別的命名物件,如型別和函式。)
實際上,甚至更通用的語法
database
.
schema
.
table
也可以使用,但目前這只是為了形式上遵守 SQL 標準。如果您寫了資料庫名稱,它必須與您連線的資料庫相同。
因此,要在新模式中建立表,請使用:
CREATE TABLE myschema.mytable ( ... );
要刪除一個模式(如果它是空的,即它裡面的所有物件都已被刪除),請使用:
DROP SCHEMA myschema;
要刪除一個模式及其包含的所有物件,請使用:
DROP SCHEMA myschema CASCADE;
有關此背後通用機制的描述,請參閱 第 5.15 節。
您可能經常希望建立一個由其他人擁有的模式(因為這是限制您的使用者在定義明確的名稱空間內的活動的方法之一)。其語法是:
CREATE SCHEMAschema_name
AUTHORIZATIONuser_name
;
您甚至可以省略模式名稱,在這種情況下,模式名稱將與使用者名稱相同。請參閱 第 5.10.6 節,瞭解這如何有用。
以 pg_
開頭的模式名稱是為系統保留的,不能由使用者建立。
在前面的章節中,我們建立了表而沒有指定任何模式名稱。預設情況下,這些表(和其他物件)會自動放入一個名為 “public” 的模式中。每個新資料庫都包含這樣一個模式。因此,以下是等效的:
CREATE TABLE products ( ... );
和
CREATE TABLE public.products ( ... );
限定名稱寫起來很麻煩,而且通常最好不要將特定的模式名稱硬編碼到應用程式中。因此,表經常透過 非限定名稱 來引用,這些名稱只包含表名。系統透過遵循一個 搜尋路徑 來確定哪個表是目標,搜尋路徑是用於查詢模式的列表。搜尋路徑中的第一個匹配的表被認為是所需的那個。如果在搜尋路徑中沒有找到匹配項,則會報告一個錯誤,即使資料庫中的其他模式中存在匹配的表名。
在不同模式中建立同名物件的能力,使得編寫每次都精確引用相同物件的查詢變得複雜。它還打開了使用者惡意或意外地更改其他使用者查詢行為的可能性。由於查詢中普遍使用非限定名稱以及它們在 PostgreSQL 內部的使用,將模式新增到 search_path
會有效地信任在該模式上具有 CREATE
許可權的所有使用者。當您執行普通查詢時,能夠建立模式物件的惡意使用者可以接管並執行任意 SQL 函式,就像您執行它們一樣。
搜尋路徑中命名的第一個模式稱為當前模式。除了是第一個被搜尋的模式之外,它也是 CREATE TABLE
命令沒有指定模式名稱時建立新表的模式。
要顯示當前的搜尋路徑,請使用以下命令:
SHOW search_path;
在預設設定下,這將返回:
search_path -------------- "$user", public
第一個元素指定要搜尋一個與當前使用者同名的模式。如果不存在這樣的模式,則忽略該條目。第二個元素指的是我們已經見過的 public 模式。
搜尋路徑中的第一個存在的模式是建立新物件的預設位置。這就是為什麼預設情況下物件在 public 模式中建立的原因。當在任何其他上下文中引用物件而不帶模式限定符(修改表、修改資料或查詢命令)時,會遍歷搜尋路徑直到找到匹配的物件。因此,在預設配置中,任何非限定訪問也只能引用 public 模式。
要將我們的新模式新增到路徑中,我們使用:
SET search_path TO myschema,public;
(我們省略了 $user
,因為我們目前不需要它。)然後我們可以不帶模式限定符來訪問表:
DROP TABLE mytable;
此外,由於 myschema
是路徑中的第一個元素,新物件預設會在此模式中建立。
我們也可以這樣寫:
SET search_path TO myschema;
然後我們就無法訪問 public 模式而沒有顯式限定符了。public 模式沒有特別之處,只是它預設存在。它也可以被刪除。
有關操作模式搜尋路徑的其他方法,請參閱 第 9.27 節。
搜尋路徑對資料型別名稱、函式名稱和運算子名稱的作用方式與對錶名稱相同。資料型別和函式名稱可以與表名稱以完全相同的方式限定。如果您需要在表示式中編寫限定的運算子名稱,有一個特殊的規定:您必須這樣寫:
OPERATOR(
schema
.
operator
)
這是為了避免語法歧義。一個例子是:
SELECT 3 OPERATOR(pg_catalog.+) 4;
實際上,人們通常依賴搜尋路徑來處理運算子,這樣就不必編寫像這樣的難看的程式碼了。
預設情況下,使用者無法訪問他們不擁有的模式中的任何物件。要允許這樣做,模式的所有者必須授予該模式的 USAGE
許可權。預設情況下,每個人都對 public
模式擁有該許可權。要允許使用者使用模式中的物件,可能需要根據物件的情況授予其他許可權。
也可以允許使用者在別人的模式中建立物件。要允許這樣做,需要授予該模式的 CREATE
許可權。在從 PostgreSQL 14 或更早版本升級的資料庫中,每個人都對 public
模式擁有該許可權。一些 使用模式 呼叫了撤銷該許可權的操作:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
(第一個 “public” 是模式,第二個 “public” 表示 “所有使用者”。第一種意義上是識別符號,第二種意義上是關鍵字,因此大小寫不同;回想一下 第 4.1.1 節 中的準則。)
除了 public
和使用者建立的模式之外,每個資料庫都包含一個 pg_catalog
模式,其中包含系統表以及所有內建資料型別、函式和運算子。pg_catalog
始終是搜尋路徑的有效組成部分。如果它沒有在路徑中明確命名,則會在搜尋路徑中的模式 之前 隱式地搜尋它。這確保了內建名稱始終可以被找到。但是,如果您希望使用者定義的名稱覆蓋內建名稱,您可以選擇將 pg_catalog
顯式地放在搜尋路徑的末尾。
由於系統表名稱以 pg_
開頭,最好避免此類名稱,以確保在未來某個版本定義了與您的表同名的系統表時,不會出現衝突。(在預設搜尋路徑下,對您的表名進行非限定引用將解析為系統表。)系統表將繼續遵循以 pg_
開頭的命名約定,因此只要使用者避免使用 pg_
字首,它們就不會與非限定的使用者表名衝突。
模式可以以多種方式用於組織資料。一個 安全的模式使用模式 可防止不受信任的使用者更改其他使用者查詢的行為。當資料庫不使用安全的模式使用模式時,希望安全地查詢該資料庫的使用者將在每個會話開始時採取保護措施。具體來說,他們將在每個會話開始時將 search_path
設定為空字串,或者從 search_path
中移除可由非超級使用者寫入的模式。預設配置可以輕鬆支援幾種使用模式:
將普通使用者限制在使用者私有模式中。要實現此模式,首先確保沒有任何模式具有公共 CREATE
許可權。然後,為每個需要建立非臨時物件的使用者,建立一個與該使用者同名的模式,例如 CREATE SCHEMA alice AUTHORIZATION alice
。(回想一下,預設搜尋路徑以 $user
開始,該變數解析為使用者名稱。因此,如果每個使用者都有單獨的模式,他們預設就可以訪問自己的模式。)此模式是安全的模式使用模式,除非不受信任的使用者是資料庫所有者或已被授予相關角色的 ADMIN OPTION
,在這種情況下,不存在安全的模式使用模式。
在 PostgreSQL 15 及更高版本中,預設配置支援此使用模式。在之前的版本中,或在使用從先前版本升級的資料庫時,您需要從 public
模式中刪除公共 CREATE
許可權(執行 REVOKE CREATE ON SCHEMA public FROM PUBLIC
)。然後考慮審計 public
模式中名稱與 pg_catalog
模式中的物件名稱相似的物件。
透過修改 postgresql.conf
或執行 ALTER ROLE ALL SET search_path = "$user"
來從預設搜尋路徑中刪除 public 模式。然後,授予在 public 模式中建立的許可權。只有限定名稱才能選擇 public 模式物件。雖然限定的表引用是可以的,但對 public 模式中函式的呼叫 可能不安全或不可靠。如果您在 public 模式中建立函式或擴充套件,請改用第一種模式。否則,與第一種模式一樣,除非不受信任的使用者是資料庫所有者或已被授予相關角色的 ADMIN OPTION
,否則此模式是安全的。
保留預設搜尋路徑,並授予在 public 模式中建立的許可權。所有使用者都隱式地訪問 public 模式。這模擬了根本不提供模式的情況,從而實現了從不熟悉模式的世界的平滑過渡。但是,這從不是安全的模式。它只在資料庫只有一個使用者或少數相互信任的使用者時才可接受。在從 PostgreSQL 14 或更早版本升級的資料庫中,這是預設設定。
對於任何模式,安裝共享應用程式(供所有人使用的表、第三方提供的附加函式等)時,將它們放入獨立的模式中。請記住授予適當的許可權以允許其他使用者訪問它們。然後,使用者可以透過用模式名稱限定名稱來引用這些附加物件,或者選擇將附加模式放入他們的搜尋路徑中。
在 SQL 標準中,同一個模式中的物件由不同使用者擁有的概念不存在。此外,一些實現不允許您建立名稱與其所有者名稱不同的模式。事實上,在只實現了標準中基本模式支援的資料庫系統中,模式和使用者的概念幾乎是等價的。因此,許多使用者認為限定名稱實際上由
組成。如果您為每個使用者建立每個使用者的模式,PostgreSQL 將會有效地這樣行為。user_name
.table_name
此外,SQL 標準中沒有 public
模式的概念。為了最大程度地符合標準,您不應使用 public
模式。
當然,一些 SQL 資料庫系統可能根本不實現模式,或者透過允許(可能受限的)跨資料庫訪問來提供名稱空間支援。如果您需要與這些系統協同工作,那麼不使用模式將實現最大的可移植性。
如果您在文件中發現任何不正確、與您在使用該特定功能時的經驗不符或需要進一步澄清的內容,請使用 此表格 來報告文件問題。