PostgreSQL数据库--database与schema

724 阅读4分钟

我正在参加「掘金·启航计划」

创建database

一个不含任何附加子句的最简单的SQL语句既可创建一个database:

create database xndb;

该命令会以template1库为模板生成一份副本并将此副本作为新的database。任何一个拥有createdb权限的角色都能够创建新的database。

模板数据库

望文生义嘛,模板数据库就是创建新的database时所使用的骨架。创建新的database时,postgressql会基于模板数据库制作一份副本,其中会包含所有数据库设置和数据文件。

postgreSQL安装后默认附带两个模板数据库,template0和template1.如果创建新的数据库未指定使用哪个模板,那么系统默认会使用template1库作为新库的模板。

你要切记一点,任何时候呢都不要去轻易修改template0模板数据库,因为合适初始的干净的数据库模板,如果其他数据库模板被破坏,基于这个数据库做个副本就可以了。当然你可以建立自己的模板数据库。

基于某个模板来创建新数据库的基本语法如下:

create database my_db template my_template_db;

当然的当然,你可以指定一个数据库为模板数据库,那么pg就会禁止对其进行修改和编辑或者删除。那要怎么做呢?

以超级用户身份运行以下的SQL可以使得任何数据库成为模板数据库。

UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'mydb';

如果你想修改或者删除被标记为模板的数据库,将上述的语句中的datistemplate字段修改为FALSE既可。

schema的使用

我们之前就有过介绍,Pg和MySQL是很不相同的,pg数据库是一个三级结构,schema呢就是第二级,schema对database中的对象进行逻辑分组。因为如果你的database中有很多的表,那么管理起来是很麻烦的,所以考虑把他们放到不同的schema去管理。同一个schema中的对象名是不允许重复的,但是同一个database中的不同的schema中的对象是可以重名的。但是如果你将数据库中的所有表都塞到默认的public schema中,那你遇到重名的对象只是迟早的问题。

比如说我们举个栗子:

举个栗子

我现在开了一家宠物店,我呢之前是将所有的数据全都存到了宠物信息都存到了一个schema里去,但是这样就有一个弊端,一个客户可以看到另一个客户的宠物信息,这是泄露隐私的,那么为了隔离客户信息,我就要你为,每个客户新建一个schema,然后在每个schema中建立同样一张dogs表。

然后呢,把这些宠物数据从单一的dogs表分拆到不同的客户的schema的dogs表中。最后为每个schema创建一个与之同名的可登录的角色。现在呢所有的宠物信息就完全被分散到他们对应的schema 下了。

当然,骚操作还没有完,我们上面为啥要让角色和schema同名呢,是为了用一个技巧:

当然在那之前,我们先介绍一下search_path 这个系统变量。前面呢,我们已经提到了同一个schema中的对象是不允许重名的,但不同的schema这种的对象可以重名。就比如说我们所有的schema里都有一张dogs表。所以这就出现一个问题,当你

\c dbname

切换到你的目标数据库执行下面的语句:

SELECT * FROM dogs;

这样的语句时,pg数据库就很懵,说它不知道你要从哪个schema中去查dogs表,解决这个问题,最简单的解决方法就是在表名前加上所属schema的名称。

image-20230221162634122

就是像上面这样。

还有另一种方法那就是通过设置search_path变量来解决。就像下面这样:

image-20230221163208729

search_path可以设置多个逗号隔开的变量,啥意思呢,就是意思会在这些schema里依次查找的意思。

书接上文,我们回到为啥要把用户名和schema设为同名,在pg中有一个罕为人知的系统变量叫做user,它代表了当前登录的用户名字。执行select user就可以看到他的值。当然系统变量user和current_user完全相同,用哪个都行。那么我们就可以这样设置 search_path变量了。

set search_path = "$user" , 另一个schema;

我们查看当前的search_path:

show search_path;

image-20230221171339152

你比如说,我们新建一个用户之后就可以这样设置search,那么下次你登录上这个角色后,select就会按照search_path的schema来检索。

还有就是你检索要先\C切换数据库呀,不然你还是搜不到数据信息。

alter role postgres  set search_path= '$user',public,李四;