在 PostgreSQL 中组织数据的一种方法是使用模式。PostgreSQL 中的模式是什么?更重要的是:模式的目的是什么以及如何使用模式让您的生活更轻松?让我们深入了解一下。
模式的目的
在弄清楚如何使用模式之前,您需要首先了解模式的用途。要理解这一点,首先看一下 PostgreSQL 的结构:
•实例
•数据库
•模式
•表
•列
“实例”基本上就是您在部署 PostgreSQL 时启动的。下一层是数据库。实际上,这就是您要连接的对象:在 PostgreSQL 中,连接始终绑定到实例内的数据库,这发生在用户身份验证之后的早期。
重要的是数据库和表之间的一层:模式。
模式组表
基本上,模式是一种将表分组在一起的方法。
让我们假设有一个相当大的数据结构:在一个地方有 500 个表肯定比有 10 个桶,每个桶包含 50 个表更难管理和理解。
这就像组织图片一样:您不会将所有图片都放在同一个文件夹中,而是按年份、位置等对它们进行分组。相同的逻辑可以应用于表格。
模式和 PostgreSQL
现在我们可以关注如何将这个概念应用于 PostgreSQL。我们首先要看的是public模式。
使用“公共”(public)模式
PostgreSQL 的美妙之处在于,即使您对模式一无所知也没关系。原因是public模式的存在,默认情况下存在。我们如何找出 PostgreSQL 中有哪些模式?
psql 提供了\dn显示此信息的命令:
demo=# \dn
List of schemas
Name | Owner
--------+-------------------
public | pg_database_owner
(1 row)
在默认情况下,表将最终出现在public模式中。这是一个例子:
demo=# CREATE TABLE t_product (
id serial,
name text,
price numeric
);
CREATE TABLE
这是一个基本表。该表可以在public模式中找到。\d将揭示真相:
demo=# \d
List of relations
Schema | Name | Type | Owner
--------+------------------+----------+-------
public | t_product | table | hs
public | t_product_id_seq | sequence | hs
(2 rows)
在这种情况下,模式和序列都按预期在默认模式中找到。如您所见,您不需要任何关于模式的知识即可继续。如果您碰巧使用了该public模式,我们还建议您查看最新版本的 PostgreSQL 中引入的新安全策略:https://www.cybertec-postgresql.com/en/error-permission-denied-schema-public/
两种查询表的方法
第一种方法是:
demo=# SELECT * FROM t_product;
id | name | price
----+------+-------
(0 rows)
查询表的另一种方法:
但是,您也可以显式地使用模式名称作为表名的前缀,这构成了一个完全限定的名称。能够降低由于配置错误而访问错误表的风险。我们稍后还会在这篇文章中看到它:
demo=# SELECT * FROM public.t_product;
id | name | price
----+------+-------
(0 rows)
在对public模式进行简要介绍之后,我们可以继续创建我们的第一个新模式。
创建模式
我们如何在 PostgreSQL 中创建模式?命令CREATE SCHEMA就是答案:
demo=# \h CREATE SCHEMA
Command: CREATE SCHEMA
Description: define a new schema
Syntax:
CREATE SCHEMA schema_name
[ AUTHORIZATION role_specification ]
[ schema_element [ ... ] ]
CREATE SCHEMA AUTHORIZATION role_specification
[ schema_element [ ... ] ]
CREATE SCHEMA IF NOT EXISTS schema_name
[ AUTHORIZATION role_specification ]
CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_specification
where role_specification can be:
user_name
| CURRENT_ROLE
| CURRENT_USER
| SESSION_USER
URL: https://www.postgresql.org/docs/15/sql-createschema.html
语法非常简单,允许我们定义名称和模式所有者。
demo=# CREATE SCHEMA warehouse;
CREATE SCHEMA
创建模式后,我们可以在模式中创建一个表:
demo=# CREATE TABLE warehouse.t_product (
prod_number text PRIMARY KEY,
d date,
in_stock int
);
CREATE TABLE
通过使用模式名称作为表名的前缀,您可以定义要使用的模式。请注意,模式本身不会影响数据的存储方式。与我们的表关联的数据文件仍然在同一个 PostgreSQL 数据目录中。因此,模式不会影响性能,也与存储优化无关。模式的目的只是将事物组合在一起,并通过为模式分配权限来帮助组织可靠的安全策略:
demo=# \d warehouse.t_product;
Table "warehouse.t_product"
Column | Type | Collation | Nullable | Default
-------------+---------+-----------+----------+---------
prod_number | text | | not null |
d | date | | |
in_stock | integer | | |
Indexes:
"t_product_pkey" PRIMARY KEY, btree (prod_number)
这里有两点值得指出:
首先,在两个不同的模式中可以有两个同名的表。有名为public.t_product和warehouse.t_product表是完全可行的,而且实际上很常见。
然后,重要的是我们不必在public模式中为表添加前缀。原因是以下参数:
demo=# SHOW search_path;
search_path
-----------------
"$user", public
(1 row)
可以直接访问要在search_path参数定义的模式名中的所有数据库对象,而无需显式提供模式名称。我们可以轻松地尝试一下:
demo=# SET search_path TO warehouse;
SET
请注意,该参数仅在您的会话中更改——如果您在交互式会话中运行它,它不会破坏您的生产系统。
从现在开始,将显示名为t_product的表,因为 PostgreSQL 知道在哪个模式中查找:
demo=# \d t_product
Table "warehouse.t_product"
Column | Type | Collation | Nullable | Default
-------------+---------+-----------+----------+---------
prod_number | text | | not null |
d | date | | |
in_stock | integer | | |
Indexes:
"t_product_pkey" PRIMARY KEY, btree (prod_number)
现在search_path已经更改了,我们必须在模式前加上前缀public,因为它不再在路径中:
demo=# \d public.t_product
Table "public.t_product"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+-----------------...
id | integer | | not null | …
name | text | | |
price | numeric | | |
在对模式进行了基本介绍之后,让我们弄清楚将模式与视图结合使用意味着什么?
视图和模式
视图是让开发人员更容易访问数据的好方法。重要的一点是模式通常不是障碍(有关视图和权限的具体细节,请参见此处)。查询可以自由地连接来自不同模式的表,并且使用查询的视图可以在您选择的模式中公开数据(假设您有这样做的权限):
demo=# SET search_path TO default;
SET
demo=# CREATE VIEW public.v AS
SELECT *
FROM warehouse.t_product ;
CREATE VIEW
但是,这对想要从 Oracle 迁移到 PostgreSQL 的人有影响。
提示:查看 CYBERTEC 迁移器
https://www.cybertec-postgresql.com/en/products/cybertec-migrator/
在 PostgreSQL 中重命名模式
在 PostgreSQL 中,所有可以创建的东西都可以重命名。模式也是如此:
demo=# \h ALTER SCHEMA
Command: ALTER SCHEMA
Description: change the definition of a schema
Syntax:
ALTER SCHEMA name RENAME TO new_name
ALTER SCHEMA name OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
URL: https://www.postgresql.org/docs/15/sql-alterschema.html
重命名模式会产生影响,这些影响在以下内容中进行了概述。注意视图发生了什么:
demo=# ALTER SCHEMA warehouse RENAME TO inventory;
ALTER SCHEMA
demo=# \d+ v
View "public.v"
Column | Type | Collation | Nullable | Default | Storage | …
-------------+---------+-----------+----------+---------+----------+ …
prod_number | text | | | | extended |
d | date | | | | plain |
in_stock | integer | | | | plain |
View definition:
SELECT t_product.prod_number,
t_product.d,
t_product.in_stock
FROM inventory.t_product;
视图不直接引用表——它引用内部对象 ID,这在这里非常重要,因为重命名模式仅意味着将不同的文本标签附加到内部 ID。视图定义不依赖于名称,因此重命名对象确实会使视图无效。在 Oracle 等数据库中,重命名对象会使视图处于无效状态。
删除模式
在 PostgreSQL 中删除模式遵循相同的逻辑:
demo=# \h DROP SCHEMA
Command: DROP SCHEMA
Description: remove a schema
Syntax:
DROP SCHEMA [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ]
URL: https://www.postgresql.org/docs/15/sql-dropschema.html
模式依赖
我们不需要孤立的对象,所以我们不能在没有附带损害的情况下丢弃它们。PostgreSQL 会准确告诉我们发生什么,但不会真正删除表——以避免破坏对模式的依赖:
demo=# DROP SCHEMA inventory;
ERROR: cannot drop schema inventory because other objects depend on it
DETAIL: table inventory.t_product depends on schema inventory
view v depends on table inventory.t_product
HINT: Use DROP ... CASCADE to drop the dependent objects too.
如果我们真的想放弃模式并面对与之相关的所有后果,CASCADE可以添加该选项:
demo=# DROP SCHEMA inventory CASCADE;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table inventory.t_product
drop cascades to view v
DROP SCHEMA
如您所见,所有依赖对象都已删除,我们留下了一个干净、一致的数据库,其中不包含任何陈旧或无效的对象。有关详细信息,请参阅Laurenz Albe 关于视图依赖项的博客:https://www.cybertec-postgresql.com/en/tracking-view-dependencies-in-postgresql/。
最后 …
即使您没有意识到,模式始终是重要的一部分;它们提供了一种以更易于理解的方式更清晰地组织数据的好方法。有关如何允许其他用户访问特定模式中的对象的更多信息,请参阅有关 ALTER DEFAULT PRIVILEGES 的博客:https://www.cybertec-postgresql.com/en/postgresql-alter-default-privileges-permissions-explained/。
本文分享自微信公众号 - 开源软件联盟PostgreSQL分会(kaiyuanlianmeng)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。