5.8. 模式
一個PostgreSQL資料庫集簇中包含一個或更多命名的資料庫。使用者和使用者組被整個集簇共享,但沒有其他資料在資料庫之間共享。任何給定用戶端連接配接隻能通路在連接配接中指定的資料庫中的資料。
注意
一個集簇的使用者并不必擁有通路集簇中每一個資料庫的權限。使用者名的共享意味着不可能在同一個集簇中出現重名的不同使用者,例如兩個資料庫中都有叫
joe
的使用者。但系統可以被配置為隻允許
joe
通路某些資料庫。
一個資料庫包含一個或多個命名模式,模式中包含着表。模式還包含其他類型的命名對象,包括資料類型、函數和操作符。相同的對象名稱可以被用于不同的模式中而不會出現沖突,例如
schema1
和
myschema
都可以包含名為
mytable
的表。和資料庫不同,模式并不是被嚴格地隔離:一個使用者可以通路他們所連接配接的資料庫中的所有模式内的對象,隻要他們有足夠的權限。
下面是一些使用模式的原因:
- 允許多個使用者使用一個資料庫并且不會互相幹擾。
- 将資料庫對象組織成邏輯組以便更容易管理。
- 第三方應用的對象可以放在獨立的模式中,這樣它們就不會與其他對象的名稱發生沖突。
模式類似于作業系統層的目錄,但是模式不能嵌套。
5.8.1. 建立模式
要建立一個模式,可使用
CREATE SCHEMA指令,并且給出選擇的模式名稱。例如:
CREATE SCHEMA myschema;
在一個模式中建立或通路對象,需要使用由模式名和表名構成的限定名,模式名和表名之間以點号分隔:
模式 . 表
在任何需要一個表名的地方都可以這樣用,包括表修改指令和後續章節要讨論的資料通路指令(為了簡潔我們在這裡隻談到表,但是這種方式對其他類型的命名對象同樣有效,例如類型和函數)。
事實上,還有更加通用的文法:
資料庫 . 模式 . 表
也可以使用,但是目前它隻是在形式上與SQL标準相容。如果我們寫一個資料庫名稱,它必須是我們正在連接配接的資料庫。
是以,如果要在一個新模式中建立一個表,可用:
CREATE TABLE myschema.mytable (
...
);
要删除一個為空的模式(其中的所有對象已經被删除),可用:
DROP SCHEMA myschema;
要删除一個模式以及其中包含的所有對象,可用:
DROP SCHEMA myschema CASCADE;
有關于此的更一般的機制請參見
第 5.13 節。
我們常常希望建立一個由其他人所擁有的模式(因為這是将使用者動作限制在良定義的名字空間中的方法之一)。其文法是:
CREATE SCHEMA schema_name AUTHORIZATION user_name;
我們甚至可以省略模式名稱,在此種情況下模式名稱将會使用使用者名,參見
第 5.8.6 節以
pg_
開頭的模式名被保留用于系統目的,是以不能被使用者所建立。
5.8.2. 公共模式
在前面的小節中,我們建立的表都沒有指定任何模式名稱。預設情況下這些表(以及其他對象)會自動的被放入一個名為“public”的模式中。任何新資料庫都包含這樣一個模式。是以,下面的指令是等效的:
CREATE TABLE products ( ... );
以及:
CREATE TABLE public.products ( ... );
5.8.3. 模式搜尋路徑
限定名寫起來很冗長,通常最好不要把一個特定模式名拉到應用中。是以,表名通常被使用非限定名來引用,它隻由表名構成。系統将沿着一條搜尋路徑來決定該名稱指的是哪個表,搜尋路徑是一個進行檢視的模式清單。 搜尋路徑中第一個比對的表将被認為是所需要的。如果在搜尋路徑中沒有任何比對,即使在資料庫的其他模式中存在比對的表名也将會報告一個錯誤。
搜尋路徑中的第一個模式被稱為目前模式。除了是第一個被搜尋的模式外,如果
CREATE TABLE
指令沒有指定模式名,它将是新建立表所在的模式。
要顯示目前搜尋路徑,使用下面的指令:
SHOW search_path;
在預設設定下這将傳回:
search_path
--------------
"$user",public
第一個元素說明一個和目前使用者同名的模式會被搜尋。如果不存在這個模式,該項将被忽略。第二個元素指向我們已經見過的公共模式。
搜尋路徑中的第一個模式是建立新對象的預設存儲位置。這就是預設情況下對象會被建立在公共模式中的原因。當對象在任何其他沒有模式限定的環境中被引用(表修改、資料修改或查詢指令)時,搜尋路徑将被周遊直到一個比對對象被找到。是以,在預設配置中,任何非限定通路将隻能指向公共模式。
要把新模式放在搜尋路徑中,我們可以使用:
SET search_path TO myschema,public;
(我們在這裡省略了
$user
,因為我們并不立即需要它)。然後我們可以該表而無需使用模式限定:
DROP TABLE mytable;
同樣,由于
myschema
是路徑中的第一個元素,新對象會被預設建立在其中。
我們也可以這樣寫:
SET search_path TO myschema;
這樣我們在沒有顯式限定時再也不必去通路公共模式了。公共模式沒有什麼特别之處,它隻是預設存在而已,它也可以被删除。
其他操作模式搜尋路徑的方法請見
第 9.25 節搜尋路徑對于資料類型名稱、函數名稱和操作符名稱的作用與表名一樣。資料類型和函數名稱可以使用和表名完全相同的限定方式。如果我們需要在一個表達式中寫一個限定的操作符名稱,我們必須寫成一種特殊的形式:
OPERATOR( schema . operator )
這是為了避免句法歧義。例如:
SELECT 3 OPERATOR(pg_catalog.+) 4;
實際上我們通常都會依賴于搜尋路徑來查找操作符,是以沒有必要去寫如此“醜陋”的東西。
5.8.4. 模式和權限
預設情況下,使用者不能通路不屬于他們的模式中的任何對象。要允許這種行為,模式的擁有者必須在該模式上授予
USAGE
權限。為了允許使用者使用模式中的對象,可能還需要根據對象授予額外的權限。
一個使用者也可以被允許在其他某人的模式中建立對象。要允許這種行為,模式上的
CREATE
權限必須被授予。注意在預設情況下,所有人都擁有在
public
模式上的
CREATE
USAGE
權限。這使得使用者能夠連接配接到一個給定資料庫并在它的
public
模式中建立對象。如果不希望允許這樣,可以撤銷該權限:
REVOKE CREATE ON SCHEMA public FROM PUBLIC;
(第一個“public”是模式,第二個“public”指的是 “每一個使用者”。第一種是一個辨別符,第二種是一個關鍵詞,是以兩者的大小寫不同。請回想
第 4.1.1 節中的指導方針。)
5.8.5. 系統目錄模式
除
public
和使用者建立的模式之外,每一個資料庫還包括一個
pg_catalog
模式,它包含了系統表和所有内建的資料類型、函數以及操作符。
pg_catalog
總是搜尋路徑的一個有效部分。如果沒有在路徑中顯式地包括該模式,它将在路徑中的模式之前被搜尋。這保證了内建的名稱總是能被找到。然而,如果我們希望用使用者定義的名稱重載内建的名稱,可以顯式的将
pg_catalog
放在搜尋路徑的末尾。
由于系統表名稱以
pg_
開頭,最好還是避免使用這樣的名稱,以避免和未來新版本中 可能出現的系統表名發生沖突。系統表将繼續采用以
pg_
開頭的方式,這樣它們不會 與非限制的使用者表名稱沖突。
5.8.6. 慣用法
模式可以被用來以多種方式組織我們的資料。在預設配置下,一些常見的用法是:
- 如果我們不建立任何模式則所有使用者會隐式地通路公共模式。這就像根本不存在模式一樣。當資料庫中隻有一個使用者或者少量合作使用者時,推薦使用這種配置。這種配置使得我們很容易從沒有模式的環境中轉換過來。
- 我們可以為每一個使用者建立與它同名的模式。回想一下,預設的搜尋路徑以
$user
開始,它将會被解析成使用者名。是以,如果每一個使用者有一個獨立的模式,它們将會預設通路自己的模式。
如果我們使用這種配置,則我們可能也希望撤銷到公共模式的通路(或者把它也一起删除),這樣使用者被真正地限制在他們自己的模式中。
- 要安裝共享的應用(任何人都可以用的表、由第三方提供的附加函數等),将它們放在獨立的模式中。記住要授予适當的權限以允許其他使用者通路它們。然後使用者就可以使用帶模式名的限定名稱來引用這些附加對象,或者他們可以把附加模式放入到他們的搜尋路徑中。
5.8.7. 可移植性
在SQL标準中,在由不同使用者擁有的同一個模式中的對象是不存在的。此外,某些實作不允許建立與擁有者名稱不同名的模式。事實上,在那些僅實作了标準中基本模式支援的資料庫中,模式和使用者的概念是等同的。是以,很多使用者認為限定名稱實際上是由
user_name
.
table_name
組成的。如果我們為每一個使用者都建立了一個模式,PostgreSQL實際也是這樣認為的。
同樣,在SQL标準中也沒有
public
模式的概念。為了最大限度的與标準一緻,我們不應使用(甚至是删除)
public
模式。
當然,某些SQL資料庫系統可能根本沒有實作模式,或者提供允許跨資料庫通路的名字空間。如果需要使用這樣一些系統,最好不要使用模式。
本文轉自PostgreSQL中文社群,原文連結: