15%

全场主机优惠15%

测试技能,享折扣

使用代码:

Skills
开始使用
24.10.2024

在 PostgreSQL 中列出和切换数据库:完整技术指南

PostgreSQL 在单个服务器实例中管理多个隔离的数据库,每个数据库都有自己的 schema、角色和权限。要列出所有数据库,可在 psql 中运行 l,或从任意会话查询 SELECT datname FROM pg_catalog.pg_database;。要切换数据库,必须打开新连接——PostgreSQL 强制执行严格的会话与数据库绑定,没有等效的会话内 USE 命令。

本指南涵盖枚举和连接 PostgreSQL 数据库的所有可用方法,从原始 psql 命令和系统目录查询,到连接字符串、pg_hba.conf 注意事项,以及生产环境中使用的多数据库工作流模式。

为什么 PostgreSQL 数据库切换的工作方式不同

大多数来自 MySQL 的开发者期望有 USE database_name; 命令。PostgreSQL 故意省略了这一功能。每个 PostgreSQL 会话在连接时绑定到恰好一个数据库,且该绑定在会话的整个生命周期内不可更改。这是一个基于 PostgreSQL 进程模型的架构决策:后端进程(postgres)在启动时将数据库的系统目录加载到共享内存中,而在会话中途切换目录无论如何都需要完整的进程重启。

提前理解这一限制可以避免数小时的调试,并有助于规划多数据库工具、连接池和应用程序配置的架构。

列出 PostgreSQL 中的所有数据库

方法 1:psql 中的 l 元命令

枚举数据库最快的方式是在交互式 psql 会话中使用 l 元命令(别名:list)。

psql -U postgres

连接后:

l

这将生成类似如下的格式化表格:

                                  List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
 myapp_db  | appuser  | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 analytics | analyst  | UTF8     | en_US.UTF-8 | en_US.UTF-8 | analyst=CTc/analyst
 postgres  | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |
 template0 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |

这些列揭示的信息不仅仅是名称:Encoding 在服务器间迁移数据时很重要,Collate 影响排序顺序和索引行为,Access privileges 使用 PostgreSQL 的 ACL 表示法(C = CONNECT,T = TEMPORARY,c = CREATE)。

要获取包括表空间和连接限制在内的扩展详情,请使用:

l+

方法 2:查询 pg_database 系统目录

对于脚本编写、监控或应用程序级内省,可直接查询 pg_catalog.pg_database 视图。由于系统目录是全局可见的,这在集群中的任何数据库中均可使用。

SELECT
    datname        AS database_name,
    pg_catalog.pg_get_userbyid(datdba) AS owner,
    pg_encoding_to_char(encoding) AS encoding,
    datcollate     AS collation,
    datctype       AS ctype,
    datconnlimit   AS connection_limit,
    pg_catalog.pg_size_pretty(pg_catalog.pg_database_size(datname)) AS size
FROM pg_catalog.pg_database
WHERE datistemplate = false
ORDER BY datname;

过滤 datistemplate = false 可从结果中排除 template0template1——这些是系统模板,而非运营数据库。datconnlimit 列在共享环境中至关重要:值为 -1 表示无限制,而任何正整数都会限制该数据库的并发连接数。

生产建议:在监控查询中添加 pg_database_size()。数据库悄然超出表空间容量是写入失败的常见原因,事后难以诊断。

方法 3:不进入 psql 即可列出数据库

对于 shell 脚本和自动化流水线,可以不进入交互式会话即可获取数据库列表:

psql -U postgres -c "l"

或获取简洁、可供脚本解析的输出:

psql -U postgres -t -c "SELECT datname FROM pg_database WHERE datistemplate = false;"
-t 标志会抑制列标题和行计数,仅返回原始值——非常适合通过管道传入 grep、awk 或 Bash 数组。
将列表导出到文件:
psql -U postgres -t -A -c "SELECT datname FROM pg_database WHERE datistemplate = false;" > db_list.txt
-A 禁用列对齐,每行输出一个数据库名称。
在 PostgreSQL 中切换数据库
由于无法在活动会话中切换数据库,正确的做法是终止当前连接并建立一个指向目标数据库的新连接。有几种高效的方式可以实现这一点。
方法 1:退出并从 shell 重新连接
在 psql 中,退出当前会话:
q
然后连接到目标数据库:
psql -U postgres -d target_database
方法 2:在 psql 中使用 c(连接)
这是交互式工作中最实用的方法。c 元命令会关闭当前连接并打开一个到指定数据库的新连接——所有操作都在同一终端会话中完成。
c target_database
也可以同时切换用户和主机:
c target_database admin_user localhost 5432
语法:c [database [username [host [port]]]]

运行 c 时,psql 将显示确认信息:

You are now connected to database "target_database" as user "postgres".

重要边界情况:如果目标数据库不存在或当前用户缺少 CONNECT 权限,c 将失败并返回到之前的连接。这比听起来更安全——您不会失去连接,但在脚本中必须通过检查退出状态来处理这种情况。

方法 3:以不同用户身份连接

以特定角色连接到数据库:

psql -d myapp_db -U appuser -h localhost -p 5432

或在现有会话中使用 c 简写:

c myapp_db appuser

这在测试行级安全(RLS)策略或验证应用程序用户无法访问其 schema 之外的表时特别有用。

方法 4:使用连接字符串(URI 格式)

PostgreSQL 支持 libpq 连接 URI 格式,将所有连接参数封装到单个字符串中。这是应用程序配置、CI/CD 流水线和基础设施即代码工具的首选方法。

psql "postgresql://appuser:password@localhost:5432/myapp_db"

或使用 postgres:// 方案(两者均有效):

psql "postgres://appuser:password@db.example.com:5432/analytics?sslmode=require"

?sslmode=require 参数强制对连接进行 TLS 加密——这是任何暴露在 localhost 之外的数据库的必要要求。如果您在 VPS独立服务器上托管 PostgreSQL,请始终将连接字符串与 sslmode=requiresslmode=verify-full 以及有效的 SSL 证书配合使用。

值得注意的连接 URI 参数:

参数用途示例值
sslmodeTLS 强制级别requireverify-full
connect_timeout连接失败前的等待秒数10
application_namepg_stat_activity 中标识客户端myapp_worker
options传递服务器端 GUC 参数-c search_path=myschema

方法 5:将 psql 与环境变量配合使用

对于频繁连接同一集群的情况,可设置环境变量以避免重复输入凭据:

export PGHOST=localhost
export PGPORT=5432
export PGUSER=postgres
export PGPASSWORD=secret   # Use .pgpass file in production instead
export PGDATABASE=myapp_db

psql

在生产环境中,使用 .pgpass 文件代替 PGPASSWORD,以避免在 shell 历史记录或进程列表中暴露凭据:

# ~/.pgpass format: hostname:port:database:username:password
localhost:5432:myapp_db:appuser:strongpassword

正确设置权限,否则 PostgreSQL 将忽略该文件:

chmod 600 ~/.pgpass

对比:数据库切换方法

方法使用场景需要新进程支持切换用户可脚本化
q + psql -dShell
c dbnamepsql 交互式否(由 psql 处理)有限
连接 URIShell / 应用程序
环境变量Shell
pgAdmin GUIGUI 客户端
连接池(PgBouncer)应用程序取决于模式

高效管理多个数据库连接

使用 pgAdmin 进行基于 GUI 的导航

pgAdmin 在左侧对象树中列出每个已注册服务器下的所有数据库。点击某个数据库并打开查询工具,所有查询将自动限定在该数据库范围内。这对于探索性工作很有用,但不适合自动化。

注意事项:pgAdmin 为每个数据库维护独立的连接槽。如果您的 PostgreSQL 服务器的 max_connections 设置较低(默认为 100),在 pgAdmin 中打开多个数据库可能会在应用程序启动之前就耗尽连接池。

使用 PgBouncer 进行连接池管理

在频繁切换数据库的生产环境中,像 PgBouncer 这样的连接池工具可以显著降低开销。PgBouncer 以三种模式运行:

  • 会话模式:每个客户端会话对应一个服务器连接。功能上等同于直接连接。
  • 事务模式:服务器连接仅在事务期间保持。对 OLTP 工作负载最为高效。
  • 语句模式:每条语句执行后归还连接。与多语句事务不兼容。

在单个 PostgreSQL 实例上运行多个应用程序数据库时——这在 VPS 托管带 cPanel 的 VPS 上是常见模式——事务模式下的 PgBouncer 可以将活跃后端进程数量减少一个数量级。

由于会话是数据库范围的,跨数据库查询数据需要使用扩展。PostgreSQL 提供两种选项:

dblink——较旧的过程式方法:

SELECT * FROM dblink(
    'dbname=analytics user=analyst host=localhost',
    'SELECT user_id, event_count FROM events WHERE date = current_date'
) AS remote(user_id INT, event_count BIGINT);

postgres_fdw——现代、符合标准的外部数据包装器:

CREATE EXTENSION postgres_fdw;

CREATE SERVER analytics_server
    FOREIGN DATA WRAPPER postgres_fdw
    OPTIONS (host 'localhost', dbname 'analytics', port '5432');

CREATE USER MAPPING FOR appuser
    SERVER analytics_server
    OPTIONS (user 'analyst', password 'secret');

CREATE FOREIGN TABLE remote_events (
    user_id INT,
    event_count BIGINT
)
SERVER analytics_server
OPTIONS (schema_name 'public', table_name 'events');

设置完成后,remote_events 的行为类似于本地表。postgres_fdw 支持谓词下推,这意味着 WHERE 子句在远程服务器上执行,而非在本地执行——这对于大型数据集来说是关键的性能区别。

系统数据库:不可触碰的内容

每个全新的 PostgreSQL 集群都包含四个数据库:

数据库用途可以连接?可以修改?
postgres默认管理数据库谨慎操作
template1CREATE DATABASE 的模板是,更改会传播
template0干净的基线模板极少
pg_catalog不是数据库,而是 schema不适用绝不

每当您运行 CREATE DATABASE 而不指定模板时,都会克隆 template1。如果您在 template1 中安装扩展或创建 schema,每个新数据库都会继承它们。这对于标准化环境很有用,但若意外操作则很危险。

template0 作为原始备用模板存在。它是在使用不同编码或区域设置恢复 pg_dump 归档时唯一可用的模板,因为它没有可能产生冲突的用户创建对象。

权限、pg_hba.conf 与连接失败

切换数据库时常见的混淆来源是 PostgreSQL 角色级权限与 pg_hba.conf 身份验证规则之间的区别。两者必须独立允许连接。

角色级检查:角色必须对目标数据库拥有 CONNECT 权限:

GRANT CONNECT ON DATABASE target_database TO appuser;

pg_hba.conf 检查:基于主机的身份验证文件(Debian/Ubuntu 上为 /etc/postgresql/15/main/pg_hba.conf)必须有与用户、数据库和源地址匹配的规则。典型条目如下:

# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    myapp_db        appuser         10.0.0.0/8              scram-sha-256

编辑 pg_hba.conf 后,无需重启服务器即可重新加载配置:

sudo systemctl reload postgresql

或在 psql 中执行:

SELECT pg_reload_conf();

常见失败模式:用户在 SQL 级别拥有 CONNECT 权限,但 pg_hba.conf 中没有匹配规则。错误消息(FATAL: no pg_hba.conf entry for host)很明确,但开发者往往完全忽略该文件,因为他们期望数据库权限完全通过 SQL 管理。

实用决策矩阵

使用此清单为您的场景选择正确的连接方式:

  • 在本地开发机器上进行交互式探索:psql 中使用 c dbname。快速,无需新进程。
  • 遍历多个数据库的 shell 脚本:在循环中使用 psql -U postgres -d $dbname -c "...",配合 -t -A 获取简洁输出。
  • 连接到单个数据库的应用程序:使用带 sslmode=require 的连接 URI 和连接池(PgBouncer 或内置驱动程序池)。
  • 需要来自两个数据库数据的应用程序:在主数据库上实现 postgres_fdw,而不是在应用程序代码中管理两个独立的连接池。
  • 验证 RLS 或权限隔离:使用 c dbname role_name 模拟目标角色,无需离开 psql
  • 自动化配置 / 基础设施即代码:使用环境变量或带服务账户的 .pgpass;切勿在脚本中硬编码凭据。
  • 高并发生产工作负载:在应用程序和 PostgreSQL 之间以事务模式部署 PgBouncer。在独立服务器上,根据硬件内存容量调整 postgresql.conf 中的 max_connections(每个后端大约使用 5–10 MB RAM)。
  • 每租户独立数据库的多租户 SaaS:考虑在单个数据库内使用基于 schema 的多租户,而非每租户独立数据库,以避免连接池碎片化并简化备份策略。

对于将 PostgreSQL 与 Web 应用程序配合运行的团队,将数据库服务器与正确配置的共享托管或 VPS 环境以及应用程序层的已注册域名配合使用,即可构成标准生产技术栈。

常见问题

我可以在不关闭 psql 会话的情况下切换数据库吗?

可以。在 psql 中使用 c target_database 元命令。它会关闭当前后端连接并打开一个到指定数据库的新连接,所有操作都在同一终端会话中完成。您还可以在同一命令中指定不同的用户、主机和端口。

为什么 PostgreSQL 没有像 MySQL 那样的 USE 命令?

PostgreSQL 的架构在启动时将后端进程绑定到单个数据库。该数据库的系统目录被加载到该进程的共享内存中,而在会话中途切换目录在架构上等同于启动一个新进程。psql 中的 c 命令是实际等效方案——它只是让进程重启对用户透明。

如何同时查询两个不同 PostgreSQL 数据库中的数据?

使用 postgres_fdw 扩展创建外部服务器和映射到远程数据库的外部表。设置完成后,您可以在单个查询中 JOIN 本地表和远程表。对于一次性查询,dblink 更简单,但性能较差且难以维护。

如果我连接到 template1 并修改它会发生什么?

您在 template1 中创建的任何对象——表、扩展、schema——都将被克隆到使用 CREATE DATABASE 创建的每个新数据库中(除非明确指定了 TEMPLATE template0)。这有时是有意为之(例如,预安装 uuid-ossppgcrypto),但意外修改可能会损坏所有后续创建的数据库。

如何查找当前 psql 会话连接的是哪个数据库?

psql 中运行以下命令:

SELECT current_database();

或查看 psql 提示符本身——默认情况下它显示 dbname=#(超级用户)或 dbname=>(普通用户),其中 dbname 是当前活动数据库。

15%

全场主机优惠15%

测试技能,享折扣

使用代码:

Skills
开始使用