本文档为PostgreSQL 9.6.0文档,本转载已得到原译者彭煜玮授权。
1. 概述
一个数据库是一些SQL对象("数据库对象")的命名集合。通常每个数据库对象(表、函数等) 属于并且只属于一个数据库(不过有几个系统表如pg_database属于整个集簇并且对集簇中的每个数据库都是可访问的)。更准确地说,一个数据库是一个模式的集合, 而模式包含表、函数等等。因此完整的层次是这样的:服务器、数据库、模式、表(或者某些其他对象类型,如函数)。
当连接到数据库服务器时,客户端必须在它的连接请求中指定它要连接的数据库名。每次连接不能访问超过一个数据库。不过,一个应用能够在同一个或者其他数据库上打开的连接数并没有受到限制。数据库是物理上相互隔离的,并且访问控制是在连接层面进行管理的。 如果一个PostgreSQL服务器实例用于承载那些应该分隔并且相互之间并不知晓的用户 和项目,那么我们建议把它们放在不同的数据库里。如果项目或者用户是相互关联的, 并且可以相互使用对方的资源,那么应该把它们放在同一个数据库里,但可能在不同的模式 中。模式只是一个纯粹的逻辑结构并且谁能访问某个模式由权限系统管理。
数据库是使用CREATE DATABASE,并且用DROP DATABASE命令删除。要确定现有数据库的集合,可以检查系统目录pg_database,例如
SELECT datname FROM pg_database;
psql程序的l元命令和-l命令行选项也可以用来列出已有的数据库。
Note:
SQL标准把数据库称作"目录",不过实际上没有区别。
2. 创建一个数据库
为了创建一个数据库,PostgreSQL服务器必须启动并运行。
数据库用 SQL 命令CREATE DATABASE创建:
CREATE DATABASE name;
其中name遵循SQL标识符的一般规则。当前角色自动成为该新数据库的拥有者。以后删除这个数据库也是该拥有者的特权(同时还会删除其中的所有对象,即使那些对象有不同的拥有者)。
因为你需要连接到数据库服务器来执行CREATE DATABASE命令, 那么还有一个问题是任意给定站点的第一个数据库是怎样创建的?第一个数据库总是由initdb命令在初始化数据存储区域时创建的。这个数据库被称为postgres。因此要创建第一个"普通"数据库时,你可以连接到postgres。
在数据库集簇初始化期间也会创建第二个数据库template1,。当在集簇中创建一个新数据库时,实际上就是克隆了template1。这就意味着你对template1所做的任 何修改都会体现在所有随后创建的数据库中。因此应避免在template1中创建对象,除非你想把它们传播到每一个新创建的数据库中。
为了方便,你还可以用一个程序来创建新数据库: createdb。
createdb dbname
createdb没什么神奇的。它连接到postgres数据库并且发出CREATE DATABASE命令,和前面介绍的完全一样。createdb参考页包含了调用细节。注意不带任何参数的createdb将创建一个使用当前用户名的数据库。
有时候你想为其他人创建一个数据库,并且使其成为新数据库的拥有者, 这样他们就可以自己配置和管理这个数据库。要实现这个目标,使用下列命令之一: 用于 SQL 环境的
CREATE DATABASE dbname OWNER rolename;
或者用于 shell 的
createdb -O rolename dbname
只有超级用户才被允许为其他人(即为一个你不是其成员的角色)创建一个数据库。
3. 模板数据库
CREATE DATABASE实际上通过拷贝一个已有数据库进行工作。默认情况下,它拷贝名为template1的标准系统数据库。所以该数据库是创建新数据库的"模板"。 如果你为template1数据库增加对象,这些对象将被拷贝到后续创建的用户数据库中。 这种行为允许对数据库中标准对象集合的站点本地修改。例如,如果你把过程语言PL/Perl安装到 template1中,那么你在创建用户数据库后不需要额外的操作就可以使用该语言。
系统里还有名为template0的第二个标准系统数据库。这个数据库包含和template1初始内容一样的数据,也就是说,只包含你的PostgreSQL版本预定义的标准对象。在数据库集簇被初始化之后,不应该对template0做任何修改。通过指示CREATE DATABASE使用template0取代template1进行拷贝,你可以创建一个"纯净的"用户数据库,它不会包含任何template1中的站点本地附加物。 这一点在恢复一个pg_dump转储时非常方便:转储脚本应该在一个纯净的数据库 中恢复以确保我们重建被转储数据库的正确内容,而不和任何现在可能已经被加入到template1中的附加物相冲突。
另一个从template0而不是template1复制的常见原因是, 可以在复制template0时指定新的编码和区域设置,而一个template1的副本必须使用和它相同的设置。这是因为的template1可能包含编码相关或区域相关的数据,而template0中没有。
要通过拷贝template0来创建一个数据库,使用:SQL 环境中的
CREATE DATABASE dbname TEMPLATE template0;
或者 shell 中的
createdb -T template0 dbname
可以创建额外的模板数据库,并且实际上可以通过将集簇中任意数据库指定为CREATE DATABASE的模板来从该数据库拷贝。不过,我们必需明白,这个功能并不是设计作为一般性的"COPY DATABASE"功能。主要的限制是当源数据库被拷贝时,不能有其他会话连接到它。如果在CREATE DATABASE开始时存在任何其它连接,那么该命令将会失败。在拷贝操作期间,到源数据库的新连接将被阻止。
对于每一个数据库在pg_database中存在两个有用的标志: datistemplate和datallowconn列。datistemplate可以被设置来指示该数据库是不是要作为CREATE DATABASE的模板。如果设置了这个标志,那么该数据库可以被任何有 CREATEDB权限的用户克隆;如果没有被设置,那么只有超级用户和该数据库的拥有者可以克隆它。如果datallowconn为假,那么将不允许与该数据库建立任何新的连接(但已有的会话不会因为把该标志设置为假而被中止)。template0通常被标记为datallowconn = false来阻止对它的修改。template0和template1通常总是被标记为datistemplate = true。
Note:
除了template1是CREATE DATABASE的默认源数据库名之外, template1和template0没有任何特殊的状态。例如,我们可以删除template1然后从template0重新创建它而不会有任何不良效果。如果我们不小心在template1中增加了一堆垃圾,那么我们就会建议做这样的操作(要删除template1,它必须有pg_database.datistemplate = false)。
当数据库集簇被初始化时,也会创建postgres数据库。这个数据库用于做为用户和应用连接的默认数据库。它只是 template1的一个拷贝,需要时可以删除并重建。
4. 数据库配置
PostgreSQL服务器提供了大量的运行时配置变量。你可以为其中的许多设置数据库相关的默认值。
例如,如果由于某种原因,你想禁用指定数据库上的GEQO优化器,正常情况下你不得不对 所有数据库禁用它,或者确保每个连接的客户端小心地发出了SET geqo TO off。要令这个设置在一个特定数据库中成为默认值,你可以执行下面的命令:
ALTER DATABASE mydb SET geqo TO off;
这样将保存该设置(但不是立即设置它)。在后续建立的到该数据库的连接中它将表现得像在会话开始后马上调用SET geqo TO off;。注意用户仍然可以在该会话中更改这个设置,它只是默认值。要撤消这样的设置,使用ALTER DATABASE dbname RESET varname。
5. 销毁一个数据库
数据库用DROP DATABASE命令删除:
DROP DATABASE name;
只有数据库的拥有者或者超级用户才可以删除数据库。删除数据库会移除其中包括的所有对象。数据库的删除不能被撤销。
你不能在与目标数据库连接时执行DROP DATABASE命令。不过,你可以连接到任何其它数据库,包括 template1数据库。template1也是你删除一个给定集簇中最后一个用户数据库的唯一选项。
为了方便,有一个在 shell 程序可以删除数据库,dropdb:
dropdb dbname
(和createdb不同,删除当前用户名的数据库不是默认动作)。
6. 表空间
PostgreSQL中的表空间允许数据库管理员在文件系统中定义用来存放表示数据库对象的文件的位置。一旦被创建,表空间就可以在创建数据库对象时通过名称引用。
通过使用表空间,管理员可以控制一个PostgreSQL安装的磁盘布局。 这么做至少有两个用处。首先,如果初始化集簇所在的分区或者卷用光了空间,而又不能在逻辑上扩展或者做别的什么操作,那么表空间可以被创建在一个不同的分区上,直到系统可以被重新配置。
其次,表空间允许管理员根据数据库对象的使用模式来优化性能。例如,一个很频繁使用的索引可以被放在非常快并且非常可靠的磁盘上,如一种非常贵的固态设备。同时,一个很少使用的或者对性能要求不高的存储归档数据的表可以存储在一个便宜但比较慢的磁盘系统上。
Warning
即便是位于主要的 PostgreSQL 数据目录之外,表空间也是数据库集簇的一部分 并且不能被视作数据文件的一个自治集合。 它们依赖于包含在主数据目录中的元数据,并且因此不能被附加到一个 不同的数据库集簇或者单独备份。类似地,如果丢失一个表空间(文件删除、磁盘失效等), 数据库集簇可能会变成不可读或者无法启动。把一个表空间放在一个临时文件系统 (如一个内存虚拟盘)上会带来整个集簇的可靠性风险。
要定义一个表空间,使用CREATE TABLESPACE命令,例如:
CREATE TABLESPACE fastspace LOCATION '/ssd1/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 TABLE和CREATE INDEX命令提供一个隐式TABLESPACE子句。
还有一个temp_tablespaces参数,它决定临时表和索引的位置,以及用于大数据集排序等目的的临时文件的位置。 这可以是一个表空间名的列表,而不是只有一个。因此,与临时对象有关的负载可以散布在多个表空间上。每次要创建一个临时对象时,将从列表中随机取一个成员来存放它。
与一个数据库相关联的表空间用来存储该数据库的系统目录。此外,如果没有给出TABLESPACE子句并且没有在default_tablespace或temp_tablespaces(如适用)中指定其他选择,它还是在该数据库中创建的表、索引和临时文件的默认表空间。如果一个数据库被创建时没有指定表空间,它会使用其模板数据库相同的表空间。
当初始化数据库集簇时,会自动创建两个表空间。pg_global表空间被用于共享系统目录。pg_default表空间是template1和template0数据库的默认表空间(并且,因此也将是所有其他数据库的默认表空间,除非被一个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将继续输出旧的表空间位置)。