21.6. 表空间

PostgreSQL里的表空间允许数据库管理员在文件系统里定义那些代表数据库对象的文件存放位置。 一旦创建了表空间,那么就可以在创建数据库对象的时候引用它。

通过使用表空间,管理员可以控制一个PostgreSQL安装的磁盘布局。 这么做至少有两个用处。首先,如果初始化集群所在的分区或者卷用光了空间, 而又不能扩展,那么表空间可以在一个不同的分区上创建和使用, 直到系统可以重新配置。

第二,表空间允许管理员根据数据库对象的使用模式安排数据位置,从而优化性能。比如, 一个很频繁使用的索引可以放在非常快并且非常可靠的磁盘上,比如一种非常贵的固态设备。而同时, 一个存储归档的数据,很少使用的或者对性能要求不高的表可以存储在一个便宜但比较慢的磁盘系统上。

要定义一个表空间,使用CREATE TABLESPACE命令,比如:

CREATE TABLESPACE fastspace LOCATION '/mnt/sda1/postgresql/data';

这个位置必须是一个现有的空目录,并且属于PostgreSQL系统用户。 所有随后在该表空间创建的对象都将被存放在这个目录下的文件里。

Note: 通常在一个逻辑文件系统上建立多个表空间没有什么意义, 因为无法控制一个逻辑文件系统里不同文件的位置。不过,PostgreSQL 并不做这方面的任何强制,并且它实际上并不知道文件系统边界。 它只知道在指定的目录里存储文件。

创建表空间本身必须用数据库超级用户身份进行,但之后你就可以允许普通数据库用户利用它了。 要做这件事情,在表空间上给这些用户授予CREATE权限。

表、索引和整个数据库都可以放在特定的表空间里。想要这么做的话, 在给定表空间上有CREATE权限的用户必须把表空间的名字以一个参数的形式传递给相关的命令。 比如,下面的命令在表空间space1上创建一个表:

CREATE TABLE foo(i int) TABLESPACE space1;

另外,还可以使用default_tablespace参数:

SET default_tablespace = space1;
CREATE TABLE foo(i int);

只要default_tablespace被设置为非空字符串, 那么它就为没有明确使用TABLESPACE子句的CREATE TABLECREATE INDEX命令提供一个隐含的子句。

也有一个temp_tablespaces参数,决定临时表和索引的放置, 就和用于像存储大数据集这样的目的临时文件一样。这可能是一个表空间名字的列表, 而不是只有一个名字,所以与临时对象相关联的负载可以散布到多个表空间中。 每次创建临时对象时选择一个随机的成员列表。

与一个数据库相关联的表空间用于存储该数据库的系统表。另外, 如果没有给出TABLESPACE子句,并且没有通过default_tablespacetemp_tablespaces(视情况而定)指定其他选项,那么在数据库中创建表, 索引和临时文件时使用的是缺省表空间。如果创建数据库时没有给它声明一个表空间, 那么它使用与它拷贝的模版数据库相同的表空间。

当数据库集群初始化时,自动创建两个表空间。pg_global表空间用于共享的系统表。 pg_defaulttemplate1template0数据库的缺省表空间 (因此,这个表空间也将是任何其它数据库的缺省表空间,除非在CREATE DATABASE 中通过TABLESPACE子句重写)。

创建了表空间之后,它就可以用于任何数据库,只要请求的用户有足够权限。 这意味着除非我们把使用这个表空间的所有数据库里的所有对象都删除掉,否则我们不能删除该表空间。

要删除一个空的表空间,使用DROP TABLESPACE命令。

检查pg_tablespace 系统表就可以获取现有的表空间,比如

SELECT spcname FROM pg_tablespace;

psql程序的\db元命令也可以用于列出现有表空间。

为了简化表空间的实现,PostgreSQL使用了符号连接。 这就意味着表空间只能在支持符号连接的系统上使用。

目录$PGDATA/pg_tblspc包含指向集群里定义的每个非内置表空间的符号连接。 尽管我们不建议,但是我们还是可能通过手工重定义这些连接来调整表空间的布局。 在服务器运行的时候不要这么干。注意在PostgreSQL 9.1及以前,你仍需要用新的位置更新 pg_tablespace表。如果你不这么做,pg_dump将继续显示旧的表空间位置。