2024年9月26日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3

5.10. 模式 #

一个 PostgreSQL 数据库集群包含一个或多个命名数据库。角色和其他一些对象类型在整个集群中共享。客户端与服务器的连接只能访问单个数据库中的数据,即连接请求中指定的数据库。

注意

集群的用户不一定具有访问集群中每个数据库的权限。角色名称共享意味着不能在同一个集群中的两个数据库中存在不同的同名角色,例如 joe;但是系统可以配置为仅允许 joe 访问某些数据库。

一个数据库包含一个或多个命名的模式,而模式又包含表。模式还包含其他类型的命名对象,包括数据类型、函数和运算符。在一个模式内,两种相同类型的对象不能具有相同的名称。此外,表、序列、索引、视图、物化视图和外部表共享相同的命名空间,因此,例如,如果索引和表位于同一个模式中,则它们必须具有不同的名称。相同的对象名称可以在不同的模式中使用而不会冲突;例如,schema1myschema 都可以包含名为 mytable 的表。与数据库不同,模式不是严格分离的:如果用户具有相应的权限,则可以访问其连接到的数据库中任何模式中的对象。

使用模式可能有多个原因

  • 允许许多用户使用一个数据库而互不干扰。

  • 将数据库对象组织成逻辑组以使其更易于管理。

  • 第三方应用程序可以放在单独的模式中,以避免与其他对象的名称冲突。

模式类似于操作系统级别的目录,但模式不能嵌套。

5.10.1. 创建模式 #

要创建模式,请使用 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 SCHEMA schema_name AUTHORIZATION user_name;

您甚至可以省略模式名称,在这种情况下,模式名称将与用户名相同。有关这如何有用,请参阅第 5.10.6 节

pg_ 开头的模式名称保留用于系统用途,用户无法创建。

5.10.2. 公共模式 #

在前面的部分中,我们创建了表而没有指定任何模式名称。默认情况下,此类表(以及其他对象)会自动放入名为 public 的模式中。每个新数据库都包含这样的模式。因此,以下内容是等效的

CREATE TABLE products ( ... );

CREATE TABLE public.products ( ... );

5.10.3. 模式搜索路径 #

限定名称写起来很麻烦,而且通常最好不要将特定的模式名称连接到应用程序中。因此,表通常通过非限定名称来引用,该名称仅包含表名称。系统通过遵循搜索路径来确定哪个表是目标,搜索路径是一个要查找的模式列表。搜索路径中第一个匹配的表将被视为所需的表。如果搜索路径中没有匹配项,则会报告错误,即使在数据库中的其他模式中存在匹配的表名称也是如此。

在不同的模式中创建同名对象的能力使编写每次引用完全相同对象的查询变得复杂。它还为用户提供了恶意或意外地更改其他用户查询行为的可能性。由于查询中非限定名称的普遍存在及其在 PostgreSQL 内部中的使用,将模式添加到 search_path 会有效地信任对该模式具有 CREATE 权限的所有用户。当您运行普通查询时,能够在您的搜索路径模式中创建对象的恶意用户可以接管并执行任意 SQL 函数,就好像您执行了它们一样。

搜索路径中第一个命名的模式称为当前模式。除了是第一个搜索的模式外,它还是在 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.27 节,了解操作模式搜索路径的其他方法。

搜索路径对数据类型名称、函数名称和运算符名称的作用方式与对表名称的作用方式相同。数据类型和函数名称可以像表名称一样进行限定。如果需要在表达式中编写限定的运算符名称,则有一个特殊规定:您必须编写

OPERATOR(schema.operator)

这是为了避免语法歧义。一个例子是

SELECT 3 OPERATOR(pg_catalog.+) 4;

在实践中,人们通常依赖于运算符的搜索路径,这样就不必编写像那样难看的任何内容了。

5.10.4. 模式和权限 #

默认情况下,用户无法访问他们不拥有的模式中的任何对象。要允许这样做,模式的所有者必须授予模式上的 USAGE 权限。默认情况下,每个人对 public 模式都具有此权限。要允许用户使用模式中的对象,可能需要根据对象授予其他权限。

也可以允许用户在其他人的模式中创建对象。要允许这样做,需要授予模式上的 CREATE 权限。在从 PostgreSQL 14 或更早版本升级的数据库中,每个人对 public 模式都具有此权限。一些使用模式需要撤销此权限

REVOKE CREATE ON SCHEMA public FROM PUBLIC;

(第一个public是模式,第二个public表示所有用户。在第一种意义上,它是一个标识符,在第二种意义上,它是一个关键字,因此大小写不同;请回顾第 4.1.1 节中的指南。)

5.10.5. 系统目录模式 #

除了public和用户创建的模式之外,每个数据库还包含一个pg_catalog模式,其中包含系统表以及所有内置数据类型、函数和运算符。pg_catalog始终有效地成为搜索路径的一部分。如果它在路径中未显式命名,则会在搜索路径中的模式之前隐式搜索它。这确保了始终可以找到内置名称。但是,如果您希望用户定义的名称覆盖内置名称,则可以显式地将pg_catalog放在搜索路径的末尾。

由于系统表名以pg_开头,因此最好避免使用此类名称,以确保在将来某个版本定义了与您的表同名的系统表时不会发生冲突。(使用默认搜索路径,对您的表名的非限定引用将被解析为系统表。)系统表将继续遵循以pg_开头的名称约定,以便只要用户避免使用pg_前缀,它们就不会与非限定的用户表名冲突。

5.10.6. 使用模式 #

模式可以用来以多种方式组织您的数据。安全模式使用模式可防止不受信任的用户更改其他用户查询的行为。当数据库不使用安全模式使用模式时,希望安全查询该数据库的用户将在每个会话的开头采取保护措施。具体来说,他们将在每个会话开始时将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 或更早版本升级的数据库中,这是默认设置。

对于任何模式,要安装共享应用程序(供所有人使用的表、第三方提供的附加函数等),请将其放入单独的模式中。请记住授予相应的权限以允许其他用户访问它们。然后,用户可以通过限定名称加上模式名称来引用这些其他对象,或者根据需要将其他模式放入其搜索路径中。

5.10.7. 可移植性 #

在 SQL 标准中,不存在同一模式中的对象由不同用户拥有的概念。此外,某些实现不允许您创建名称与其所有者不同的模式。实际上,在仅实现标准中指定的 basic 模式支持的数据库系统中,模式和用户的概念几乎等效。因此,许多用户认为限定名称实际上由user_name.table_name组成。如果您为每个用户创建一个每个用户的模式,那么PostgreSQL 将有效地表现出这种行为。

此外,SQL 标准中没有public模式的概念。为了最大程度地符合标准,您不应使用public模式。

当然,某些 SQL 数据库系统可能根本不实现模式,或者通过允许(可能有限的)跨数据库访问来提供命名空间支持。如果您需要使用这些系统,则要实现最大可移植性,则根本不应使用模式。

提交更正

如果您在文档中发现任何不正确的内容,与您对特定功能的体验不符,或者需要进一步说明,请使用此表单报告文档问题。