PostgreSQL 数据库集群包含一个或多个命名的数据库。角色和少数其他对象类型跨越整个集群共享。到服务器的客户端连接只能访问单个数据库中的数据,即在连接请求中指定的数据。
群集的用户不一定有权访问群集中的每个数据库。共享角色名称意味着在同一群集中的两个数据库中不能有名称不同的角色,比如 joe
;但系统可以配置为仅允许 joe
访问其中一些数据库。
数据库包含一个或多个名为 模式 的数据库,进而包含表格。模式还包含其他种类的命名对象,包括数据类型、函数和运算符。在同一个模式内,同一类型的两个对象不能有相同的名称。此外,表格、序列、索引、视图、物化视图和外部表格共享相同的名称空间,所以,例如,如果索引和表格在同一模式内,则它们必须有不同的名称。同样的对象名称可以在不同的模式中使用,而不会发生冲突;例如, schema1
和 myschema
都可以包含名为 mytable
的表格。与数据库不同,模式没有严格区分:用户可以访问他们有权访问的数据库中的任何模式中的对象。
有几个原因可能导致有人要使用模式
允许许多用户使用一个数据库而不相互干扰。
将数据库对象组织成逻辑组,以便于管理。
可以将第三方应用程序放入单独的模式,以便它们不会与其他对象名称冲突。
模式类似于操作系统级别的目录,不同之处在于模式无法嵌套。
要创建模式,请使用 创建模式 命令。按自己选择给模式命名。例如
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
第一个元素指定与当前用户同名的模式需要进行搜索。如果不存在此类模式,该条将被忽略。第二个元素引用我们已经看到的公共模式。
搜索路径中存在的第一个模式是创建新对象时的默认位置。这就是默认情况下在公共模式中创建对象的原因。当在没有任何架构限定符的情况下(表修改、数据修改或查询命令)的其他上下文中引用对象时,搜索路径将被遍历直至找到匹配对象。因此,在默认配置中,任何不合格的访问都只能再次引用公共模式。
为了将我们的新模式加入路径,我们使用
SET search_path TO myschema,public;
(我们在此处省略$user
,因为我们不需要它。)随后我们就可以在没有架构限定符的情况下访问表
DROP TABLE mytable;
而且,由于 模式
是路径中的第一个元素,默认情况下将在其中创建新对象。
我们还可以编写
SET search_path TO myschema;
随后,如果没有明确的限定符,我们就无法再访问公共模式。公共模式没有什么特别之处,除了它在默认情况下存在。它也可以被删除。
另请参阅第 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"
来从默认搜索路径中删除公共模式。然后,在公共模式中授予创建权限。只有限定名称会选择公共模式对象。虽然限定表引用很好,但调用公共模式中的函数 是不安全或不可靠的。如果您在公共模式中创建函数或扩展,请改用第一个模式。否则,与第一个模式一样,只有当不受信任的用户是数据库所有者或已授予相关角色 ADMIN OPTION
时,这是安全的。
保留默认搜索路径,并在公共模式中授予创建权限。所有用户都隐式访问公共模式。这模拟了根本没有模式的情况,从与模式无关的世界中提供平稳过渡。但是,这永远不是一个安全的模式。仅当数据库具有单个用户或几个相互信任的用户时,才可接受。在从 PostgreSQL 14 或更早版本升级的数据库中,这是默认设置。
对于任何模式,要安装共享应用程序(大家使用的表、第三方提供的附加函数等),请将它们放入单独的模式中。别忘了授予适当的权限,以允许其他用户访问它们。然后,用户可以通过使用模式名称限定名称来引用这些附加对象,或者他们可以选择将附加模式放入他们的搜索路径中。
在 SQL 标准中,不存在同个模式中的对象由不同用户拥有的概念。此外,某些实施不允许您创建名称与其所有者不同的模式。事实上,在仅实现标准中指定的模式基本支持的数据库系统中,模式和用户概念几乎相同。因此,许多用户认为限定名称实际上由
组成。如果您为每个用户创建每个用户模式,这是 PostgreSQL 将实际采用的方式。user_name
.table_name
此外,SQL 标准中没有 public
模式的概念。为了最大限度地符合标准,您不应该使用 public
模式。
当然,某些 SQL 数据库系统可能根本不实现模式,或者通过允许(可能是有限的)跨数据库访问来提供命名空间支持。如果您需要使用这些系统,那么完全不使用模式将实现最大的可移植性。