跳转到内容

PostgreSQL

来自 Arch Linux 中文维基

PostgreSQL是一个开源的,社区驱动的,符合标准的 对象-关系型 数据库系统。


安装

[编辑 | 编辑源代码]
警告:在升级到新版本的 PostgreSQL 包前,请先查看 #升级 PostgreSQL 一节中的必要步骤。

安装 postgresql 包。这同时会创建一个名为 postgres 的系统用户。

你现在可以通过提权工具来切换到 postgres 用户下。

初始化配置

[编辑 | 编辑源代码]

在 PostgreSQL 可以正常使用之前,数据库集群必须被初始化:

[postgres]$ initdb -D /var/lib/postgres/data

其中 -D 提供了数据库集群的默认数据存放位置(如果需要修改目录位置,可以参考#修改默认数据目录)。initdb 也支持多种其它的命令行参数:

这篇文章的某些内容需要扩充。

原因:PostgreSQL 还支持 ICU 区域设置。[1] (在 Talk:PostgreSQL 中讨论)


  • 默认情况下,数据库集群的区域设置和编码 是从当前环境中派生的(使用 $LANG 值)。如果这不是你想要的,你可以使用 --locale=locale(其中 locale 是从系统的 可用区域设置 中选择的)和 --encoding=encoding(必须与选择的区域设置匹配)来覆盖默认值。(一旦数据库启动,你可以使用 [postgres]$ psql -l 检查使用了哪些值。)
    注意:使用除 C.UTF-8CPOSIXucs_basic 以外的区域设置可能会导致 排序规则版本不匹配,如果提供区域设置的库(glibcicu)更新,则需要重新索引。
  • 如果数据目录所在的文件系统没有数据校验和功能,你可能会想要启用 PostgreSQL 自带的 校验和 功能来提高数据完整性保障 - 使用 --data-checksums 参数即可。相关细节可参考 #Enable data checksumming。(一旦数据库启动,你可以使用 [postgres]$ psql --tuples-only -c "SHOW data_checksums" 检查是否启用了该功能。)
注意:/var/lib/postgres/data/ 目录设置了 CNo_COWfile attribute[2] 这会在 Btrfs禁用校验和
  • 默认使用 trust 认证方法,这意味着主机上的任何人都可以以任何数据库用户身份连接。你可以使用 --auth-local=peer --auth-host=scram-sha-256 来使用更安全的认证方法。
  • -c/--set 选项可用于设置任何 postgresql.conf 参数,避免手动编辑 postgresql.conf 的需要。
  • 更多选项,请参阅 initdb --help官方文档

示例:

[postgres]$ initdb --locale=C.UTF-8 --encoding=UTF8 -D /var/lib/postgres/data --data-checksums

屏幕上应该会出现许多行,其中几行以 ... ok 结尾:

The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "C.UTF-8".
The default text search configuration will be set to "english".

Data page checksums are enabled.

creating directory /var/lib/postgres/data ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting default time zone ... UTC
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

initdb: warning: enabling "trust" authentication for local connections
initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    pg_ctl -D /var/lib/postgres/data -l logfile start

如果你看到的是这些行,那么初始化过程成功了。使用 exit 返回到普通用户。

警告:
提示:如果你将根目录更改为 /var/lib/postgres 以外的路径,你将需要 编辑 服务文件。如果根目录在 home 下,请确保将 ProtectHome 设置为 false。

最后,启动启用 postgresql.service 服务。

创建第一个数据库/用户

[编辑 | 编辑源代码]
提示:如果你创建一个与你的 Linux 用户名相同的 PostgreSQL 角色/用户,它将允许你在访问 PostgreSQL 数据库 shell 时无需指定登录用户(这非常方便)。

以 postgres 用户身份,使用 createuser 命令添加一个新的数据库角色/用户:

[postgres]$ createuser --interactive

使用 createdb 命令,创建一个上述用户可以读写的新数据库(如果数据库用户与你的 Linux 用户名相同,请从你的登录 shell 执行此命令,否则请在以下命令中添加 -O database-username):

$ createdb myDatabaseName
提示:如果你没有授予新用户数据库创建权限,请在上述命令中添加 -U postgres

熟悉 PostgreSQL

[编辑 | 编辑源代码]

连接数据库 shell

[编辑 | 编辑源代码]

以 postgres 用户身份登录。启动主数据库 shell psql,在这里你可以创建/删除数据库和表、配置权限以及运行原始 SQL 命令。使用 -d 选项连接到你创建的数据库(如果不指定数据库,psql 会尝试连接与你用户名同名的数据库)。

[postgres]$ psql -d myDatabaseName

一些有用的命令:

  • 获取帮助
=> \help
  • 列出所有数据库
=> \l
  • 连接到特定数据库
=> \c database
  • 列出所有用户以及他们的权限
=> \du
  • 展示当前数据库中所有的表相关的汇总信息
=> \dt
  • 退出 psql
=> \q 或是 Ctrl+d

当然也有更多元命令,但这些应该能够帮助您开始。要查看所有元命令:

=> \?

可选配置

[编辑 | 编辑源代码]

PostgreSQL 数据库服务器的配置文件是 postgresql.conf。该文件位于服务器的数据目录中,通常为 /var/lib/postgres/data。该目录还包含其他主要配置文件,包括定义认证设置的 pg_hba.conf,适用于本地用户其他主机用户

注意:默认情况下,普通用户无法浏览或搜索此目录。这就是为什么 findlocate 无法找到配置文件的原因。

默认限制数据库超级用户的访问权限

[编辑 | 编辑源代码]

默认情况下,pg_hba.conf 允许任何本地用户以任何数据库用户身份连接,包括数据库超级用户。 这可能不是您想要的,因此为了限制对 postgres 用户的全局访问,请更改以下行:

/var/lib/postgres/data/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" 仅用于 Unix 域套接字连接
local   all             all                                     trust

改为:

/var/lib/postgres/data/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" 仅用于 Unix 域套接字连接
local   all             postgres                                peer

您可以根据需要或软件要求稍后添加其他行。

要求登录密码

[编辑 | 编辑源代码]

编辑 /var/lib/postgres/data/pg_hba.conf 并将每个用户(或 all 以影响所有用户)的认证方法设置为 scram-sha-256

/var/lib/postgres/data/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD 

# "local" 仅用于 Unix 域套接字连接
local   all             user                                    scram-sha-256
注意:更改 pg_hba.conf 中的认证方法不会更新数据库中存储的哈希密码 [3]。要从 md5 迁移到 scram-sha-256,您需要为每个数据库用户设置新密码。

重启 postgresql.service,然后使用 ALTER USER user WITH ENCRYPTED PASSWORD 'password'; 重新添加每个用户的密码。

配置 PostgreSQL 仅通过 UNIX 套接字访问

[编辑 | 编辑源代码]

最初创建集群时,将 -c listen_addresses='' 附加到 initdb 命令中。

对于现有集群,编辑 postgresql.conf 并在连接和认证部分设置:

/var/lib/postgres/data/postgresql.conf
listen_addresses = ''

这将完全禁用网络监听。 之后,您应该重启 postgresql.service 以使更改生效。

配置 PostgreSQL 以允许远程主机访问

[编辑 | 编辑源代码]

在连接和认证部分,根据需要设置 listen_addresses 行:

/var/lib/postgres/data/postgresql.conf
listen_addresses = 'localhost,my_local_ip_address'

您可以使用 '*' 来监听所有可用地址。

注意:PostgreSQL 默认使用 TCP 端口 5432 进行远程连接。确保此端口在您的防火墙中打开并能够接收传入连接。您也可以在配置文件中更改此端口,位于 listen_addresses 下方。

然后在认证配置中添加如下行:

/var/lib/postgres/data/pg_hba.conf
# TYPE  DATABASE        USER            ADDRESS                 METHOD
# IPv4 本地连接:
host    all             all             ip_address/32           scram-sha-256

其中 ip_address 是远程客户端的 IP 地址。

请参阅 pg_hba.conf 的文档。

注意:

本文或本章节的事实准确性存在争议。

原因: 官方文档指出 md5 使用挑战-响应认证,这"防止了密码嗅探"。也许不应将其视为与明文发送密码一样不安全。(在 Talk:PostgreSQL 中讨论)



如果未通过 SSL 安全连接发送,无论是发送明文密码还是 md5 哈希值都不安全。请参阅 使用 SSL 保护 TCP/IP 连接 以了解如何配置 PostgreSQL 使用 SSL。

之后,您应该重启 postgresql.service 以使更改生效。

要进行故障排除,请查看服务器日志文件:

# journalctl -u postgresql.service

配置 PostgreSQL 使用 PAM 认证

[编辑 | 编辑源代码]

PostgreSQL 提供了多种认证方法。如果您希望允许用户使用其系统密码进行认证,则需要执行额外的步骤。首先,您需要为连接启用 PAM

例如,与上述相同的配置,但启用了 PAM:

/var/lib/postgres/data/pg_hba.conf
# IPv4 本地连接:
host   all   all   my_remote_client_ip_address/32   pam

然而,PostgreSQL 服务器在没有 root 权限的情况下运行,无法访问 /etc/shadow。我们可以通过允许 postgres 组访问此文件来解决此问题:

# setfacl -m g:postgres:r /etc/shadow

修改默认数据目录

[编辑 | 编辑源代码]

默认设置下,新创建的数据库会被存放于 /var/lib/postgres/data 目录下。如果要更改目录位置,可以参考下列步骤:

创建一个新文件夹,并将其所有者设为 postgres 用户:

# mkdir -p /pathto/pgroot/data
# chown -R postgres:postgres /pathto/pgroot

切换到 postgres 用户,然后初始化新集群:

[postgres]$ initdb -D /pathto/pgroot/data

通过编辑 postgresql.service附加配置片段,以覆盖 EnvironmentPIDFile 设置。例如:

/etc/systemd/system/postgresql.service.d/PGROOT.conf
[Service]
Environment=PGROOT=/pathto/pgroot
PIDFile=/pathto/pgroot/data/postmaster.pid

如果您想使用 /home 目录作为默认目录或用于表空间,需要在此文件中额外添加一行:

ProtectHome=false

将新数据库的默认编码更改为 UTF-8

[编辑 | 编辑源代码]
注意:如果您在运行 initdb 时使用了 -E UTF8 或在使用 UTF-8 区域设置时,这些步骤不是必需的。

在创建新数据库时(例如使用 createdb blog),PostgreSQL 实际上会复制一个模板数据库。有两个预定义的模板:template0 是原始的,而 template1 是供管理员更改的现场模板,默认情况下使用。要更改新数据库的编码,其中一个选项是更改现场 template1。为此,登录到 PostgreSQL shell(psql)并执行以下操作:

首先,我们需要删除 template1。模板无法直接删除,因此我们首先将其修改为普通数据库:

UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template1';

现在我们可以删除它:

DROP DATABASE template1;

下一步是从 template0 创建一个新数据库,并使用新的默认编码:

CREATE DATABASE template1 WITH TEMPLATE = template0 ENCODING = 'UNICODE';

现在将 template1 修改为实际模板:

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

可选地,如果您不希望任何人连接到此模板,请将 datallowconn 设置为 FALSE

UPDATE pg_database SET datallowconn = FALSE WHERE datname = 'template1';
注意:最后一步在使用 pg_upgrade 升级时可能会产生问题。

现在您可以创建一个新数据库:

[postgres]$ createdb blog

如果您重新登录到 psql 并检查数据库,您应该看到新数据库的正确编码:

\l
                              List of databases
  Name    |  Owner   | Encoding  | Collation | Ctype |   Access privileges
-----------+----------+-----------+-----------+-------+----------------------
blog      | postgres | UTF8      | C         | C     |
postgres  | postgres | SQL_ASCII | C         | C     |
template0 | postgres | SQL_ASCII | C         | C     | =c/postgres
                                                     : postgres=CTc/postgres
template1 | postgres | UTF8      | C         | C     |

启用数据校验和

[编辑 | 编辑源代码]

如果您的数据库文件位于没有校验和的文件系统上,其数据可能会因位衰减和硬件故障而遭受静默数据损坏。虽然这些事件很少见,但如果您关心数据完整性,您可能希望启用 PostgreSQL 的内置数据校验和。此功能必须在集群级别启用,而不是按数据库或按表启用。

注意:此功能有一些注意事项:
  • 存在 最小的性能影响,尤其是在从磁盘读取大型数据集时。内存操作不受影响。
  • PostgreSQL 无法修复损坏的数据 - 它只会中止从损坏页面读取的事务,以防止进一步的损坏或无效的执行结果。
  • 校验和仅覆盖磁盘数据(行)页面,不包括元数据或控制结构。内存页面不进行校验和。纠错存储和 ECC 内存仍然有益。
  • 要在集群创建期间启用校验和,请将 --data-checksums 参数添加到 initdb
  • 要验证是否启用了校验和,请运行 [postgres]$ psql --tuples-only -c "SHOW data_checksums"(应打印 offon)。
  • 要在现有集群上切换校验和:
  1. 停止 postgresql.service
  2. 运行 [postgres]$ pg_checksums --pgdata /var/lib/postgres/data --enable(或 --disable 如果您不再需要校验和)。启用校验和将重写所有数据库页面,对于大型数据库实例,这将需要一些时间。
  3. 启动 postgresql.service

图形化管理工具

[编辑 | 编辑源代码]
  • phpPgAdmin — 基于 Web 的 PostgreSQL 管理工具。
https://github.com/phppgadmin/phppgadmin || phppgadminAUR
  • pgAdmin-desktop — pgAdmin 的桌面用户界面,一个全面的 PostgreSQL 设计和管理的图形用户界面。
https://www.pgadmin.org/ || pgadmin4-desktopAUR
  • pgAdmin — 全面的 PostgreSQL 设计和管理图形用户界面。
https://www.pgadmin.org/ || pgadmin4[损坏的链接:package not found]
  • pgModeler — PostgreSQL 的图形化模式设计工具。
https://pgmodeler.io/ || pgmodelerAUR
  • Postbird — 跨平台的 PostgreSQL 图形用户界面客户端,使用 JavaScript 编写,基于 Electron 运行。
https://github.com/paxa/postbird || postbird-binAUR
  • rainfrog — Postgres 的数据库管理 TUI。
https://github.com/achristmascarl/rainfrog || rainfrog
  • pgweb — 跨平台的 PostgreSQL 数据库 Web 客户端。
https://sosedoff.github.io/pgweb || pgweb-binAUR

支持多种数据库管理系统的工具,请参见 List of applications/Documents#Database tools

设置备份

[编辑 | 编辑源代码]

建议为包含重要数据的数据库设置备份。请参阅 PostgreSQL 文档中的 备份与恢复 章节。PostgreSQL 维基中还有一个 备份工具列表,尽管它可能不是最新的或完整的。请记住,除非您定期执行测试恢复,否则不能信任备份系统!

升级 PostgreSQL

[编辑 | 编辑源代码]

这篇文章的某些内容需要扩充。

原因:How to upgrade when using third party extensions? (在 Talk:PostgreSQL#pg_upgrade problem if extensions (like postgis) are used 中讨论)

升级 PostgreSQL 大版本(例如从 14.x 升级到 15.y)需要一些额外的维护工作。

注意:应遵循 PostgreSQL 官方的 升级文档
警告:以下指令可能导致数据丢失。不要盲目运行下面的命令,确保你理解它们在做什么。请先备份

通过以下命令获取当前使用的数据库版本:

# cat /var/lib/postgres/data/PG_VERSION

为了避免意外升级到不兼容的数据库版本,建议 跳过更新 PostgreSQL 包。

小版本升级是安全的。然而,如果你意外升级到一个不同的大版本,你可能无法访问任何数据。请务必查看 PostgreSQL 主页 以确认每个升级所需的步骤。有关为什么会出现这种情况的更多信息,请参阅 版本策略

有两种主要的方法可以升级你的 PostgreSQL 数据库。请阅读官方文档以获取详细信息。

pg_upgrade

[编辑 | 编辑源代码]

pg_upgrade 工具尝试在集群之间复制尽可能多的兼容数据,并升级其他所有内容。尽管它需要访问源和目标 PostgreSQL 版本的二进制文件,但它通常是升级大多数实例的最快方法。请阅读 pg_upgrade(1) 手册页以了解它执行的操作。对于非平凡的实例(例如带有流复制或日志传送的实例),请先阅读 上游文档

对于希望使用 pg_upgrade 的用户,有一个 postgresql-old-upgrade 包,它将始终运行比实际 PostgreSQL 包低一个主要版本的版本。这可以与新版本的 PostgreSQL 一起安装。要从旧版本的 PostgreSQL 升级,可以使用 AUR 包,例如 postgresql-12-upgradeAUR。(你必须使用与你升级到的 PostgreSQL 版本打包的 pg_upgrade 版本。)

请注意,数据库集群目录不会随版本变化而变化,因此在运行 pg_upgrade 之前,有必要重命名现有的数据目录并迁移到一个新目录。必须使用与旧集群相同的参数初始化新的数据库集群。

当你准备好开始升级时:

  1. 当旧数据库集群仍在运行时,收集用于创建它的 initdb 参数。请参阅 #初始化配置 以获取更多信息。
  2. 停止 postgresql.service。检查 单元状态确保 PostgreSQL 已正确停止。如果停止失败,pg_upgrade 将失败并显示 The source cluster was not shut down cleanly
  3. 升级 postgresql, postgresql-libs, 和 postgresql-old-upgrade
  4. 确保 /var/lib/postgres/olddata 不存在。如果你在上次升级后没有删除它,请现在删除。
  5. 重命名旧集群目录,然后创建一个新的集群和临时工作目录:
    # mv /var/lib/postgres/data /var/lib/postgres/olddata
    # mkdir /var/lib/postgres/data /var/lib/postgres/tmp
    # chown postgres:postgres /var/lib/postgres/data /var/lib/postgres/tmp
    [postgres]$ cd /var/lib/postgres/tmp
    
  6. 使用与旧集群相同的 initdb 参数初始化新集群:
    [postgres]$ initdb -D /var/lib/postgres/data --locale=C.UTF-8 --encoding=UTF8 --data-checksums
  7. 升级集群,将下面的 PG_VERSION 替换为旧的 PostgreSQL 版本号(例如 15):
    [postgres]$ pg_upgrade -b /opt/pgsql-PG_VERSION/bin -B /usr/bin -d /var/lib/postgres/olddata -D /var/lib/postgres/data
    提示:在支持 reflinks 的文件系统(例如 BtrfsXFS)上,可以附加 --clone 选项以加快文件复制速度。
    如有必要,调整新集群的配置文件(例如 pg_hba.confpostgresql.conf)以匹配旧集群。
  8. 再次启动postgresql.service
  9. 可选: 运行 [postgres]$ vacuumdb --all --analyze-in-stages 以重新计算查询分析器统计信息,这 应该会在升级后不久提高查询性能。(添加 --jobs=NUMBER_OF_CPU_CORES 参数可能会提高此命令的性能。)
  10. 可选: 备份 /var/lib/postgres/olddata 目录,以防你需要恢复之前的 PostgreSQL 版本。
  11. 删除包含旧集群数据的 /var/lib/postgres/olddata 目录。
  12. 删除 /var/lib/postgres/tmp 目录。
  13. 如果你使用 pgbackrest,请运行 stanza-upgrade 命令。

手动转储和重新加载

[编辑 | 编辑源代码]

你也可以这样做(在升级并安装 postgresql-old-upgrade 之后)。

注意:
  • 以下是升级自 PostgreSQL 14 的命令。你可以在 /opt/ 中找到适用于你 PostgreSQL 集群版本的类似命令,前提是你安装了相应版本的 postgresql-old-upgrade 包。
  • 如果你自定义了 pg_hba.conf 文件,你可能需要临时修改它以允许从本地系统完全访问旧数据库集群。升级完成后,将你的自定义设置应用到新数据库集群并 restart postgresql.service

停止 postgresql.service

# mv /var/lib/postgres/data /var/lib/postgres/olddata
# mkdir /var/lib/postgres/data
# chown postgres:postgres /var/lib/postgres/data
[postgres]$ initdb -D /var/lib/postgres/data --locale=C.UTF-8 --encoding=UTF8 --data-checksums
[postgres]$ /opt/pgsql-14/bin/pg_ctl -D /var/lib/postgres/olddata/ start
# cp /usr/lib/postgresql/postgis-3.so /opt/pgsql-14/lib/ # 仅当安装了 postgis 时
[postgres]$ pg_dumpall -h /tmp -f /tmp/old_backup.sql
[postgres]$ /opt/pgsql-14/bin/pg_ctl -D /var/lib/postgres/olddata/ stop

启动 postgresql.service

[postgres]$ psql -f /tmp/old_backup.sql postgres

故障排除

[编辑 | 编辑源代码]

提高小事务的性能

[编辑 | 编辑源代码]

如果你在本地机器上使用 PostgresSQL 进行开发,并且感觉速度较慢,可以尝试在配置中关闭 synchronous_commit。但请注意 注意事项

警告:这是一个非常粗糙的解决方案,可能会破坏数据库或导致数据丢失,因此请务必备份。

使用扩展时包更新后 PostgreSQL 数据库无法启动

[编辑 | 编辑源代码]

这种情况通常是因为现有扩展包没有针对新版本编译(尽管扩展包本身可能是最新的),解决方案是重新构建扩展包,可以手动操作或等待扩展包更新。

升级带有扩展的数据库版本时无法启动旧版本 PostgreSQL 服务器

[编辑 | 编辑源代码]

这是因为 postgresql-old-upgrade 提供的旧版本 postgres 在其 lib 目录中没有所需的扩展(.so 文件)。目前的解决方案比较粗糙,可能会引发很多问题,因此请务必先备份数据库。基本思路是将所需的扩展 .so 文件从 /usr/lib/postgresql/ 复制到 /opt/pgsql-XX/lib/(记得将 XX 替换为 postgresql-old-upgrade 的主版本号)。

例如,对于 timescaledb:

# cp /usr/lib/postgresql/timescaledb*.so /opt/pgsql-13/lib/
警告:虽然复制 .so 文件对我来说已经足够,但可能需要将更多文件复制到 /opt/pgsql-XX/ 下的正确目录中。

要了解需要复制的确切文件,可以使用以下命令检查扩展包的内容:

$ pacman -Ql package_name
警告:这是一个非常粗糙的解决方案,可能会破坏数据库或导致数据丢失,因此请务必备份。

警告:数据库 "postgres" 的排序规则版本不匹配

[编辑 | 编辑源代码]

你可能会看到类似这样的信息:

WARNING:  database "postgres" has a collation version mismatch
DETAIL:  The database was created using collation version X.YY, but the operating system provides version X.ZZ.
HINT:  Rebuild all objects in this database that use the default collation and run ALTER DATABASE postgres REFRESH COLLATION VERSION, or build PostgreSQL with the right library version.

这意味着排序规则提供库(glibcicu)已更新,可能使某些索引失效。因此需要重新索引这些数据库。

可以通过以下命令操作:

[postgres]$ psql -c 'REINDEX DATABASE' postgres
[postgres]$ psql -c 'ALTER DATABASE postgres REFRESH COLLATION VERSION'

对于其他数据库,只需将上述命令中的 postgres 替换为相应的数据库名称并重复执行。

提示:使用 C.UTF-8CPOSIXucs_basic 区域设置创建数据库集群可以避免此问题。