codecamp

PostgreSQL 创建一个数据库集簇

18.2.1. 二级文件系统的使用
18.2.2. 文件系统

在你能做任何事情之前,你必须在磁盘上初始化一个数据库存储区域。我们称之为一个数据库集簇SQL标准使用的术语是目录集簇)。一个数据库集簇是被一个运行数据库服务器的单一实例所管理的多个数据库的集合。在初始化之后,一个数据库集簇将包含一个名为postgres的数据库,它表示被功能、用户和第三方应用所使用的默认数据库。数据库服务器本身并不要求 postgres数据库存在。另一个在初始化过程中为每一个集簇创建的数据库被称为template1。顾名思义,它将被用于创建后续数据库的模板;它不应该被用于实际工作(在集簇内创建新数据库的更多信息请见第 22 章)。

在文件系统术语中,一个数据库集簇是一个单一目录,所有数据都将被存储在其中。我们称它为数据目录数据区域。在哪里存储你的数据完全由你选择。没有默认的位置,不过/usr/local/pgsql/data/var/lib/pgsql/data位置比较流行。 数据目录必须在使用前初始化,必须使用与 PostgreSQL一起安装的程序initdb

如果您使用的是 PostgreSQL 的预打包版本,它可能有一个特定的约定来放置数据目录的位置,并且它还可能提供用于创建数据目录的脚本。 在这种情况下,您应该优先使用该脚本而不是直接运行 initdb。 有关详细信息,请参阅包级文档。

要手动初始化数据库集群,请运行 initdb 并使用 -D 选项指定所需的数据库集群文件系统位置,例如:

$ initdb -D /usr/local/pgsql/data

请注意,您必须在登录 PostgreSQL 用户帐户时执行此命令,这在上一节中进行了描述。

提示

作为-D选项的一种替换方案,你可以设置环境变量PGDATA

另一种替代方案是,你可以通过pg_ctl 程序来运行initdb

$ pg_ctl -D /usr/local/pgsql/data initdb

如果你使用pg_ctl来启停服务器(见第 18.3 节),这种方法可能更直观,以为这样pg_ctl将是你用来管理数据库服务器实例的唯一命令。

如果你指定的目录还不存在,initdb将尝试创建它。当然,如果initdb没有在父目录中的写权限,这将会失败。通常推荐让PostgreSQL用户拥有数据目录及其父目录,这样就不存在上面的问题了。如果想要的父目录也不存在,你将需要先创建它,如果父父目录不可写则使用 root 特权。因此,该过程可能像这样:

root# mkdir /usr/local/pgsqlroot# chown postgres /usr/local/pgsqlroot# su postgrespostgres$ initdb -D /usr/local/pgsql/data      

如果数据目录存在并且已经包含文件,initdb将拒绝运行。这可以避免无意中覆盖一个已有的安装。

因为数据目录包含所有存储在数据库里的数据,所以最重要的是保护这个目录不受未授权的访问。因此,initdb会回收禁止除PostgreSQL用户,也可以选择组,之外所有用户的访问权限。当组访问启用时,是只读的。它允许相同组中未被授权的用户作为集簇属主,备份集簇数据或者执行其他只需要读访问权限的操作。

注意在现有集群启用或禁用组访问时,需要关闭集群,且重新启动PostgreSQL之前设置所有的目录和文件到恰当的模式。否则,数据目录中会存在多种模式。集群仅可以被其属主访问,恰当的模式应该是,其目录设置为0700,普通文件设置为0600。允许集群被组可读,恰当的模式应该是,其目录设置为0750,普通文件设置为 0640

不过,虽然目录的内容是安全的,但默认的客户端认证设置允许任意本地用户连接到数据库甚至成为数据库超级用户。如果你不信任其他本地用户, 我们建议你使用initdb-W--pwprompt--pwfile选项之一给数据库超级用户赋予一个口令。 还可以指定-A md5-A password,这样就不会使用默认的trust 身份认证。或者在执行initdb之后、第一次启动服务器之前修改生成的pg_hba.conf文件(另外一些可行的方法包括 peer认证或者用文件系统权限限制连接。更多信息见第 20 章)。

initdb同时也为数据库集簇初始化默认区域 。 通常,它将只是使用环境中的区域设置并且把它们应用于被初始化的数据库。 可以为数据库指定一个不同的区域;有关于此的更多信息可以在第 23.1 节中找到。 特定数据库集簇中使用的默认排序顺序是通过initdb设置的, 虽然你可以创建使用不同排序顺序的新数据库,但在 initdb 创建的模板数据库中使用的顺序不能更改(除非删除并重建它们)。使用非 CPOSIX的区域还会对性能造成影响。因此,第一次就正确地选择很重要。

initdb还为数据库集簇设置默认的字符集编码。通常字符集编码应该选择与区域设置匹配。详见第 23.3 节

C以及非POSIX区域对于字符集排序依赖于操作系统的排序规则库。这控制着索引中存储的键的排序。为此,通过快照恢复、二进制流复制、更换不同的操作系统或者升级操作系统都不能把一个集簇切换到一种不兼容的排序规则库版本。

18.2.1. 二级文件系统的使用

很多安装会在文件系统(卷)而不是机器的卷上创建它们的数据库集簇。如果你选择这样做,我们不建议尝试使用二级卷的顶层目录(挂载点)作为数据目录。最好的做法是在PostgreSQL用户拥有的挂载点目录中创建一个目录,然后在其中创建数据目录。这可以避免权限问题,特别是对于pg_upgrade这类操作,并且它也能在二级卷被断线后确保干净的失败。

18.2.2. 文件系统

通常来说,任何具有 POSIX 语义的文件系统都可用于 PostgreSQL。用户出于各种原因会喜欢不同的文件系统,包括供应商支持、性能和熟悉程度等。 经验表明,在其他方面相同的情况下,人们不应期望仅仅通过切换文件系统或进行较小的文件系统配置调整以造成明显的性能或行为更改。

18.2.2.1. NFS

可以用 NFS文件系统来存储 PostgreSQL数据目录。 PostgreSQL没有特殊对待NFS文件系统,这意味着它假定NFS的行为与本地连接的驱动器完全一样。 PostgreSQL不使用任何已知在NFS上非标准的功能,例如文件锁定。

PostgreSQL使用NFS 的唯一硬性要求是,文件系统需要使用 hard 选项挂载。 使用hard选项,如果存在网络问题,进程可以无限期地hang,因此这个配置需要仔细的监视设置。 soft选项将在出现网络问题时中断系统调用,但 PostgreSQL 不会重复系统呼叫以这种方式中断,因此任何此类中断都将导致报告 I/O 错误。

sync挂载选项不是必须的。 async选项的特性是足够的,因为 PostgreSQL 发出 fsync调用,会在适当的时候刷新写缓存。(这与它在本地文件系统上的工作方式相类似。) 但是,强烈建议在部署NFS server 的系统上使用 sync导出选项(主要是Linux)。 否则,NFS 客户端上的 fsync 或等效项实际上不能保证实现服务器上的永久存储,这可能会导致损坏,类似于使用参数 fsync关闭。 这些挂载和导出选项的默认值在供应商和版本之间有所不同,因此建议在任何情况下检查并明确指定它们,以避免任何歧义。

在某些情况下,可以通过 NFS 或较低级别的协议,例如 iSCSI,访问外部存储产品。 在后一种情况下,存储显示为块设备,可以在其上创建任何可用的文件系统。 这种方法可能会使 DBA 不必处理 NFS 的一些特性,但是在其他级别当然会出现管理远程存储的复杂性。


PostgreSQL PostgreSQL用户账户
PostgreSQL 启动数据库服务器
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

PostgreSQL SQL语言

PostgreSQL 服务器管理

PostgreSQL 客户端接口

PostgreSQL 服务器编程

PostgreSQL 参考

PostgreSQL 内部

PostgreSQL 附录

PostgreSQL 参考书目

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }