PostgreSQL 模式

2021-08-26 10:36 更新
5.9.1. 創(chuàng)建模式
5.9.2. 公共模式
5.9.3. 模式搜索路徑
5.9.4. 模式和權(quán)限
5.9.5. 系統(tǒng)目錄模式
5.9.6. 使用模式
5.9.7. 可移植性

一個(gè)PostgreSQL數(shù)據(jù)庫集簇中包含一個(gè)或更多命名的數(shù)據(jù)庫。 角色和一些其他對(duì)象類型被整個(gè)集簇共享,連接到服務(wù)器的客戶端只能訪問單個(gè)數(shù)據(jù)庫中的數(shù)據(jù),在連接請(qǐng)求中指定的那一個(gè)。

注意

一個(gè)集簇的用戶并不必?fù)碛性L問集簇中每一個(gè)數(shù)據(jù)庫的權(quán)限。 角色名的共享意味著不可能在同一個(gè)集簇中出現(xiàn)重名的不同角色,例如兩個(gè)數(shù)據(jù)庫中都有叫joe的用戶。 但系統(tǒng)可以被配置為只允許joe訪問某些數(shù)據(jù)庫。

一個(gè)數(shù)據(jù)庫包含一個(gè)或多個(gè)命名模式,模式中包含著表。模式還包含其他類型的命名對(duì)象,包括數(shù)據(jù)類型、函數(shù)和操作符。相同的對(duì)象名稱可以被用于不同的模式中二不會(huì)出現(xiàn)沖突,例如schema1myschema都可以包含名為mytable的表。和數(shù)據(jù)庫不同,模式并不是被嚴(yán)格地隔離:一個(gè)用戶可以訪問他們所連接的數(shù)據(jù)庫中的所有模式內(nèi)的對(duì)象,只要他們有足夠的權(quán)限。

下面是一些使用方案的原因:

  • 允許多個(gè)用戶使用一個(gè)數(shù)據(jù)庫并且不會(huì)互相干擾。

  • 將數(shù)據(jù)庫對(duì)象組織成邏輯組以便更容易管理。

  • 第三方應(yīng)用的對(duì)象可以放在獨(dú)立的模式中,這樣它們就不會(huì)與其他對(duì)象的名稱發(fā)生沖突。

模式類似于操作系統(tǒng)層的目錄,但是模式不能嵌套。

5.9.1. 創(chuàng)建模式

要?jiǎng)?chuàng)建一個(gè)模式,可使用CREATE SCHEMA命令,并且給出選擇的模式名稱。例如:

CREATE SCHEMA myschema;

在一個(gè)模式中創(chuàng)建或訪問對(duì)象,需要使用由模式名和表名構(gòu)成的限定名,模式名和表名之間以點(diǎn)號(hào)分隔:

schema.table

在任何需要一個(gè)表名的地方都可以這樣用,包括表修改命令和后續(xù)章節(jié)要討論的數(shù)據(jù)訪問命令(為了簡(jiǎn)潔我們?cè)谶@里只談到表,但是這種方式對(duì)其他類型的命名對(duì)象同樣有效,例如類型和函數(shù))。

事實(shí)上,還有更加通用的語法:

database.schema.table

也可以使用,但是目前它只是在形式上與SQL標(biāo)準(zhǔn)兼容。如果我們寫一個(gè)數(shù)據(jù)庫名稱,它必須是我們正在連接的數(shù)據(jù)庫。

因此,如果要在一個(gè)新模式中創(chuàng)建一個(gè)表,可用:

CREATE TABLE myschema.mytable (
 ...
);

要?jiǎng)h除一個(gè)為空的模式(其中的所有對(duì)象已經(jīng)被刪除),可用:

DROP SCHEMA myschema;

要?jiǎng)h除一個(gè)模式以及其中包含的所有對(duì)象,可用:

DROP SCHEMA myschema CASCADE;

有關(guān)于此的更一般的機(jī)制請(qǐng)參見第 5.14 節(jié)

我們常常希望創(chuàng)建一個(gè)由其他人所擁有的模式(因?yàn)檫@是將用戶動(dòng)作限制在良定義的名字空間中的方法之一)。其語法是:

CREATE SCHEMA schema_name AUTHORIZATION user_name;

我們甚至可以省略模式名稱,在此種情況下模式名稱將會(huì)使用用戶名,參見本文中的“5.9.6. 使用模式”。

pg_開頭的模式名被保留用于系統(tǒng)目的,所以不能被用戶所創(chuàng)建。

5.9.2. 公共模式

在前面的小節(jié)中,我們創(chuàng)建的表都沒有指定任何模式名稱。默認(rèn)情況下這些表(以及其他對(duì)象)會(huì)自動(dòng)的被放入一個(gè)名為public的模式中。任何新數(shù)據(jù)庫都包含這樣一個(gè)模式。因此,下面的命令是等效的:

CREATE TABLE products ( ... );

以及:

CREATE TABLE public.products ( ... );

5.9.3. 模式搜索路徑

限定名寫起來很冗長(zhǎng),通常最好不要把一個(gè)特定模式名拉到應(yīng)用中。因此,表名通常被使用非限定名來引用,它只由表名構(gòu)成。系統(tǒng)將沿著一條搜索路徑來決定該名稱指的是哪個(gè)表,搜索路徑是一個(gè)進(jìn)行查看的模式列表。 搜索路徑中第一個(gè)匹配的表將被認(rèn)為是所需要的。如果在搜索路徑中沒有任何匹配,即使在數(shù)據(jù)庫的其他模式中存在匹配的表名也將會(huì)報(bào)告一個(gè)錯(cuò)誤。

在不同方案中創(chuàng)建命名相同的對(duì)象的能力使得編寫每次都準(zhǔn)確引用相同對(duì)象的查詢變得復(fù)雜。這也使得用戶有可能更改其他用戶查詢的行為,不管是出于惡意還是無意。由于未經(jīng)限定的名稱在查詢中以及在PostgreSQL內(nèi)部的廣泛使用,在search_path中增加一個(gè)方案實(shí)際上是信任所有在該方案中具有CREATE特權(quán)的用戶。在你運(yùn)行一個(gè)普通查詢時(shí),惡意用戶可以在你的搜索路徑中的以方案中創(chuàng)建能夠奪取控制權(quán)并且執(zhí)行任意SQL函數(shù)的對(duì)象,而這些事情就像是你在執(zhí)行一樣。

搜索路徑中的第一個(gè)模式被稱為當(dāng)前模式。除了是第一個(gè)被搜索的模式外,如果CREATE TABLE命令沒有指定模式名,它將是新創(chuàng)建表所在的模式。

要顯示當(dāng)前搜索路徑,使用下面的命令:

SHOW search_path;

在默認(rèn)設(shè)置下這將返回:

 search_path
--------------
 "$user", public

第一個(gè)元素說明一個(gè)和當(dāng)前用戶同名的模式會(huì)被搜索。如果不存在這個(gè)模式,該項(xiàng)將被忽略。第二個(gè)元素指向我們已經(jīng)見過的公共模式。

搜索路徑中的第一個(gè)模式是創(chuàng)建新對(duì)象的默認(rèn)存儲(chǔ)位置。這就是默認(rèn)情況下對(duì)象會(huì)被創(chuàng)建在公共模式中的原因。當(dāng)對(duì)象在任何其他沒有模式限定的環(huán)境中被引用(表修改、數(shù)據(jù)修改或查詢命令)時(shí),搜索路徑將被遍歷直到一個(gè)匹配對(duì)象被找到。因此,在默認(rèn)配置中,任何非限定訪問將只能指向公共模式。

要把新模式放在搜索路徑中,我們可以使用:

SET search_path TO myschema,public;

(我們?cè)谶@里省略了$user,因?yàn)槲覀儾⒉涣⒓葱枰H缓笪覀兛梢詣h除該表而無需使用方案進(jìn)行限定:

DROP TABLE mytable;

同樣,由于myschema是路徑中的第一個(gè)元素,新對(duì)象會(huì)被默認(rèn)創(chuàng)建在其中。

我們也可以這樣寫:

SET search_path TO myschema;

這樣我們?cè)跊]有顯式限定時(shí)再也不必去訪問公共模式了。公共模式?jīng)]有什么特別之處,它只是默認(rèn)存在而已,它也可以被刪除。

其他操作模式搜索路徑的方法請(qǐng)見第 9.26 節(jié)

搜索路徑對(duì)于數(shù)據(jù)類型名稱、函數(shù)名稱和操作符名稱的作用與表名一樣。數(shù)據(jù)類型和函數(shù)名稱可以使用和表名完全相同的限定方式。如果我們需要在一個(gè)表達(dá)式中寫一個(gè)限定的操作符名稱,我們必須寫成一種特殊的形式:

OPERATOR(schema.operator)

這是為了避免句法歧義。例如:

SELECT 3 OPERATOR(pg_catalog.+) 4;

實(shí)際上我們通常都會(huì)依賴于搜索路徑來查找操作符,因此沒有必要去寫如此“丑陋”的東西。

5.9.4. 模式和權(quán)限

默認(rèn)情況下,用戶不能訪問不屬于他們的方案中的任何對(duì)象。要允許這種行為,模式的擁有者必須在該模式上授予USAGE權(quán)限。為了允許用戶使用方案中的對(duì)象,可能還需要根據(jù)對(duì)象授予額外的權(quán)限。

一個(gè)用戶也可以被允許在其他某人的模式中創(chuàng)建對(duì)象。要允許這種行為,模式上的CREATE權(quán)限必須被授予。注意在默認(rèn)情況下,所有人都擁有在public模式上的CREATEUSAGE權(quán)限。這使得用戶能夠連接到一個(gè)給定數(shù)據(jù)庫并在它的public模式中創(chuàng)建對(duì)象?;厥者@一特權(quán)的 “5.9.6. 使用模式“調(diào)用:

REVOKE CREATE ON SCHEMA public FROM PUBLIC;

(第一個(gè)public是方案,第二個(gè)public指的是每一個(gè)用戶。第一種是一個(gè)標(biāo)識(shí)符,第二種是一個(gè)關(guān)鍵詞,所以兩者的大小寫不同。請(qǐng)回想第 4.1.1 標(biāo)識(shí)符和關(guān)鍵詞節(jié)中的指導(dǎo)方針。)

5.9.5. 系統(tǒng)目錄模式

public和用戶創(chuàng)建的模式之外,每一個(gè)數(shù)據(jù)庫還包括一個(gè)pg_catalog模式,它包含了系統(tǒng)表和所有內(nèi)建的數(shù)據(jù)類型、函數(shù)以及操作符。pg_catalog總是搜索路徑的一個(gè)有效部分。如果沒有在路徑中顯式地包括該模式,它將在路徑中的模式之前被搜索。這保證了內(nèi)建的名稱總是能被找到。然而,如果我們希望用用戶定義的名稱重載內(nèi)建的名稱,可以顯式的將pg_catalog放在搜索路徑的末尾。

由于系統(tǒng)表名稱以pg_開頭,最好還是避免使用這樣的名稱,以避免和未來新版本中 可能出現(xiàn)的系統(tǒng)表名發(fā)生沖突。系統(tǒng)表將繼續(xù)采用以pg_開頭的方式,這樣它們不會(huì) 與非限制的用戶表名稱沖突。

5.9.6. 使用模式

模式能夠以多種方式組織數(shù)據(jù).secure schema usage pattern防止不受信任的用戶更改其他用戶查詢的行為。 當(dāng)數(shù)據(jù)庫不使用安全模式使用方式時(shí),希望安全地查詢?cè)摂?shù)據(jù)庫的用戶將在每個(gè)會(huì)話開始時(shí)采取保護(hù)操作。 具體的說,他們將通過設(shè)置search_path到空字符串或在其它情況下從search_path中刪除非超級(jí)用戶可寫的模式來開始每個(gè)會(huì)話。 默認(rèn)配置可以很容易的支持一些使用模式。

  • 將普通用戶約束在其私有的方案中。要實(shí)現(xiàn)這一點(diǎn),發(fā)出REVOKE CREATE ON SCHEMA public FROM PUBLIC,并且為每一個(gè)用戶創(chuàng)建一個(gè)用其用戶名命名的方案。 回想一下以$user開頭的默認(rèn)搜索路徑,該路徑解析為用戶名。 因此,如果每個(gè)用戶都有單獨(dú)的模式,則默認(rèn)情況下他們?cè)L問自己的模式。 在不受信任的用戶已經(jīng)登錄的數(shù)據(jù)庫中采用此模式后,請(qǐng)考慮審計(jì)名字類似于模式pg_catalog中的對(duì)象的公共模式。 此方式是一種安全模式的使用方式,除非不受信任的用戶是數(shù)據(jù)庫所有者或擁有CREATEROLE權(quán)限,在這種情況下沒有安全模式使用方式存在。

  • 從默認(rèn)搜索路徑中刪除公共模式,通過修改postgresql.conf或通過發(fā)出ALTER ROLE ALL SET search_path ="$user"。 每一個(gè)都保留在公共模式中創(chuàng)建對(duì)象的能力,但是只有符合資格的名稱才會(huì)選擇這些對(duì)象。 雖然符合資格的表引用是可以的,但是要調(diào)用公共模式中的函數(shù)will be unsafe or unreliable。 如果在公共模式中創(chuàng)建函數(shù)或擴(kuò)展,請(qǐng)改用第一個(gè)方式。 否則,與第一個(gè)模式一樣,這是安全的,除非不受信任的用戶是數(shù)據(jù)庫所有者或擁有CREATEROLE權(quán)限。

  • 保持默認(rèn)。所有用戶都隱式地訪問公共模式。這模擬了方案根本不可用的情況,可以用于從無模式感知的世界平滑過渡。 但是,這絕不是一個(gè)安全的模式。只有當(dāng)數(shù)據(jù)庫僅有單個(gè)用戶或者少數(shù)相互信任的用戶時(shí),才可以接受。

對(duì)于任何一種模式,為了安裝共享的應(yīng)用(所有人都要用其中的表,第三方提供的額外函數(shù),等等),可把它們放在單獨(dú)的方案中。記住授予適當(dāng)?shù)奶貦?quán)以允許其他用戶訪問它們。然后用戶可以通過以方案名限定名稱的方式來引用這些額外的對(duì)象,或者他們可以把額外的方案放在自己的搜索路徑中。

5.9.7. 可移植性

在SQL標(biāo)準(zhǔn)中,在由不同用戶擁有的同一個(gè)模式中的對(duì)象是不存在的。此外,某些實(shí)現(xiàn)不允許創(chuàng)建與擁有者名稱不同名的模式。事實(shí)上,在那些僅實(shí)現(xiàn)了標(biāo)準(zhǔn)中基本模式支持的數(shù)據(jù)庫中,模式和用戶的概念是等同的。因此,很多用戶認(rèn)為限定名稱實(shí)際上是由user_name.table_name組成的。如果我們?yōu)槊恳粋€(gè)用戶都創(chuàng)建了一個(gè)模式,PostgreSQL實(shí)際也是這樣認(rèn)為的。

同樣,在SQL標(biāo)準(zhǔn)中也沒有public模式的概念。為了最大限度的與標(biāo)準(zhǔn)一致,我們不應(yīng)使用(甚至是刪除)public模式。

當(dāng)然,某些SQL數(shù)據(jù)庫系統(tǒng)可能根本沒有實(shí)現(xiàn)方案,或者提供允許跨數(shù)據(jù)庫訪問的名字空間。如果需要使用這樣一些系統(tǒng),最好不要使用方案。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)