Ubuntu 20.04 PostgreSQL安装配置全指南:APT/二进制/源码三方案深度对比
1. 项目概述:为什么在 Ubuntu 20.04 上亲手装好 PostgreSQL 比“一键安装”重要十倍
PostgreSQL 不是那种装完就扔的玩具数据库。它是个有脾气、讲规矩、重细节的工业级数据引擎——你今天跳过一个字符集配置,三个月后业务表里突然冒出一堆问号;你忽略 locale 设置,某天凌晨三点收到告警:全文检索返回空结果,而客户订单正卡在支付确认页。我在金融系统和地理信息平台干了八年 DBA,亲眼见过太多人把sudo apt install postgresql当成终点,结果在生产环境栽在 pg_hba.conf 的一行 trust 配置上,或者被默认的 shared_buffers 值拖垮整台服务器内存。Ubuntu 20.04 是 LTS 版本,内核稳定、社区支持长,但它的 PostgreSQL 包版本(默认 12.18)早已不是最新主力,而很多新项目需要 14+ 的逻辑复制增强或 15 的增量备份功能。所以“安装”这件事,本质是一次对数据底座的主权声明:你要决定用哪个源、编译参数怎么调、服务如何守护、权限从哪一层开始收口。这不是命令行敲几下就能交差的事,而是要像调试电路板一样,每个开关位置都得心里有数。本文不讲“三分钟上手”,只拆解真实场景中你必须面对的每一个决策点:为什么选 APT 而非源码?systemd 服务文件里RestartSec=30是防什么?pg_dump 的-Fc和-Ft格式在恢复时到底差在哪?这些细节,决定了你的数据库是稳如磐石,还是随时可能在高并发下抖三抖。
2. 安装方案深度对比:APT、官方二进制包、源码编译,哪条路踩坑最少
2.1 APT 方案:Ubuntu 官方仓库的“安全但陈旧”路径
Ubuntu 20.04 默认仓库里的 PostgreSQL 是 12.x 系列,这是经过 Canonical 严格测试、与系统内核和 libc 兼容性已验证的版本。它的优势极其明确:依赖自动解决、systemd 服务开箱即用、安全更新随 Ubuntu 补丁同步推送。我给客户做合规审计时,这条路径最容易通过——因为所有二进制文件哈希值都在 Ubuntu Security Team 的签名清单里可查。但代价是功能滞后:比如 JSONB 的@?操作符(PostgreSQL 12.2 才引入)在 12.1 就不可用;又比如pg_stat_statements扩展的track_utility参数,在 12.0 里默认关闭且无法动态开启,而监控慢查询必须靠它。实测过一个 GIS 项目,用 APT 安装的 12.1 运行ST_DWithin函数时,空间索引命中率比 14.5 低 37%,直接导致地图瓦片生成延迟翻倍。所以如果你的项目只需要基础 CRUD、对新特性无强依赖,且团队运维能力偏弱,APT 是最省心的选择。执行命令就是两行:
sudo apt update sudo apt install -y postgresql postgresql-contrib安装后,服务自动启动,数据目录在/var/lib/postgresql/12/main,配置文件在/etc/postgresql/12/main/。注意:postgresql-contrib必须装,否则pg_trgm(模糊搜索)、hstore(键值对)这些高频扩展全不可用。
2.2 官方二进制包:PostgreSQL Global Development Group 的“精准控制”方案
当你需要特定小版本(比如必须用 14.11 修复某个 WAL 日志解析 bug),或想避开 Ubuntu 自定义的 systemd 单元文件(某些企业环境禁止修改/lib/systemd/system/下的文件),官方二进制包是黄金选择。它由 PostgreSQL 官方团队编译,针对 glibc 2.31(Ubuntu 20.04 默认)做了优化,且提供.tar.gz和.deb两种格式。.deb包能用dpkg -i安装,但不会自动创建用户和数据目录——这反而是优势:你可以把数据盘挂载到/data/pg14,日志盘单独挂到/log/pg14,彻底隔离 I/O。我给一家物流公司的订单库升级时,就是用官方.deb包覆盖安装,全程未停服:先在新路径初始化集群,再用pg_dumpall --globals-only导出角色和表空间,最后用pg_basebackup做物理复制,整个过程比 APT 升级快 40%。下载地址是https://www.postgresql.org/download/linux/ubuntu/,关键操作是解压后运行./configure的替代品——官方包自带install.sh脚本,它会检查/usr/local/pgsql是否存在,若不存在则创建,并将二进制文件、共享库、头文件分门别类放好。重点提醒:官方包不带postgresql-contrib,你得单独下载对应版本的 contrib 包,否则citext(大小写不敏感文本)这类扩展会报ERROR: could not open extension control file。
2.3 源码编译:为极致性能和定制化付出的“硬核代价”
源码编译不是炫技,而是当你的硬件有特殊需求时的唯一解法。比如你用的是 AMD EPYC 7742 处理器,想启用--with-llvm编译 JIT(即时编译)加速复杂表达式计算;又或者你的存储是 NVMe SSD 阵列,需要调整--with-system-tzdata指向更精确的时区数据库。我曾为一个实时风控系统编译 PostgreSQL 15.3,启用了--enable-thread-safety(线程安全)和--with-openssl(强制 TLS 1.3),编译参数长达 27 行。但代价巨大:在 Ubuntu 20.04 上,你需要先装build-essential、libreadline-dev、zlib1g-dev、libssl-dev、libxml2-dev、libxslt1-dev六个核心依赖,漏一个就会在make阶段报错。更致命的是时间成本:在 16 核 CPU 上,make -j16编译耗时 18 分钟,make install再加 3 分钟。而一旦编译完成,你就完全掌控了所有开关:shared_preload_libraries可以预加载自定义 C 扩展,pg_stat_statements.max能设到 10000(默认 5000),这些在二进制包里都是写死的。所以我的建议很直白:除非你有明确的性能瓶颈报告(比如EXPLAIN ANALYZE显示 JIT 未生效),或者安全策略强制要求所有二进制文件必须自编译签名,否则别碰源码。它就像一把瑞士军刀,功能全,但日常切水果,用菜刀更快。
2.4 方案决策树:一张表帮你锁定最适合的路径
| 判断条件 | 推荐方案 | 关键原因 | 实操风险提示 |
|---|---|---|---|
| 项目处于 PoC 验证阶段,需快速跑通 demo | APT | 5 分钟内完成,无依赖冲突 | sudo apt autoremove可能误删 postgresql 包,务必加--dry-run预览 |
| 生产环境要求长期支持(LTS),且无新特性刚需 | APT | Ubuntu 安全补丁自动同步,审计友好 | 数据目录/var/lib/postgresql/12/main权限为700,普通用户无法直接读取 WAL 文件 |
| 需要 PostgreSQL 14+,且服务器不允许修改系统仓库 | 官方二进制包 | 版本精准可控,安装路径自由指定 | 官方.deb包的postinst脚本会尝试启动服务,若端口被占用会失败,需提前sudo ss -tuln | grep :5432 |
| 硬件为 ARM64 架构(如 AWS Graviton2) | 源码编译 | 官方二进制包仅提供 x86_64,ARM 需手动编译 | ./configure时必须加--host=aarch64-linux-gnu,否则编译出的二进制在 ARM 上无法运行 |
| 需集成 pgvector(AI 向量搜索)或 timescaledb(时序数据) | 官方二进制包 + 手动扩展安装 | 这些扩展的预编译二进制仅适配官方包,APT 版本需自行编译扩展 | pgvector的.so文件必须放在$PGHOME/lib,而非/usr/lib/postgresql/12/lib/ |
提示:无论选哪种方案,安装后第一件事是执行
sudo -u postgres psql -c "SELECT version();"。如果返回PostgreSQL 12.18 (Ubuntu 12.18-0ubuntu0.20.04.1),说明你装的是 APT 版本;若返回PostgreSQL 14.11 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 10.3.0-1ubuntu3~20.04) 10.3.0, 64-bit,则是官方二进制包。这个命令能立刻验明正身,避免后续配置走错方向。
3. 初始化与核心配置:从initdb到postgresql.conf的每一行都关乎生死
3.1 初始化集群:initdb的隐藏参数比你想象的更重要
很多人以为sudo pg_createcluster 14 main(APT 方式)或sudo /usr/lib/postgresql/14/bin/initdb -D /data/pg14(官方包)就是全部,其实initdb的参数组合决定了数据库的“基因”。比如-E UTF8指定编码,这没问题;但-U postgres指定超级用户名,如果你改成-U dbadmin,那后续所有psql -U postgres命令都会失败——因为postgres用户根本不存在。更关键的是--locale参数:initdb -D /data/pg14 --locale=C和--locale=en_US.UTF-8的区别,远不止语言显示。Clocale 使用字节序比较,排序极快,适合日志分析类应用;而en_US.UTF-8支持 Unicode 归类规则,但ORDER BY性能下降 15%-20%。我做过压测:1000 万行用户表按姓名排序,Clocale 耗时 1.2 秒,en_US.UTF-8耗时 1.8 秒。所以如果你的业务不涉及多语言排序(比如纯英文电商后台),--locale=C是必选项。另一个常被忽略的是--auth-local和--auth-host:它们控制本地 socket 和 TCP 连接的默认认证方式。--auth-local=peer(Unix socket 用系统用户认证)比--auth-local=md5更安全,因为无需密码传输;而--auth-host=md5对远程连接是底线要求。执行初始化后,务必检查/data/pg14/global/pg_filenode.map文件是否存在——这是集群的“DNA 文件”,若缺失,pg_resetwal工具将无法工作,意味着 WAL 日志损坏时无法强制恢复。
3.2postgresql.conf:12 个必须调整的核心参数详解
postgresql.conf是 PostgreSQL 的心脏起搏器,改错一个参数,轻则性能骤降,重则服务崩溃。下面这 12 个参数,是我从上百个生产环境故障中提炼出的“生死线”。
listen_addresses = 'localhost'
默认值是'localhost',非常安全。但如果你需要远程连接(比如应用服务器在另一台机器),必须改成'localhost,192.168.1.100'(填应用服务器 IP),绝不能写'0.0.0.0'。后者等于把数据库大门敞开,任何能访问该端口的人都能尝试爆破。我处理过一个案例:开发为图方便设成0.0.0.0,三天后发现数据库被植入挖矿脚本,CPU 占用 99%。max_connections = 200
默认 100,对小型项目够用。但每增加一个连接,PostgreSQL 就要分配约 10MB 内存(含 work_mem)。200 连接意味着额外 2GB 内存开销。计算公式:总内存 = shared_buffers + (max_connections × work_mem) + (max_connections × temp_buffers)。所以调高max_connections前,先算清你的 RAM 是否撑得住。shared_buffers = 2GB
这是 PostgreSQL 的主缓存区,绝不应超过物理内存的 25%。Ubuntu 20.04 默认是 128MB,太小。假设你有 16GB 内存,shared_buffers设为 2GB(2048MB)是黄金值。设太大反而有害:Linux 内核的 page cache 会和它争内存,导致磁盘 I/O 激增。实测过:32GB 内存服务器设shared_buffers=12GB,TPS(每秒事务数)反而比设4GB低 22%。work_mem = 16MB
每个查询操作(排序、哈希连接)能使用的内存量。默认 4MB,对复杂 JOIN 是灾难。设为 16MB 后,一个含 5 张表 JOIN 的报表查询,执行时间从 42 秒降到 8.3 秒。但注意:work_mem是按每个操作分配的,一个查询若有 3 个排序,就消耗3×16MB=48MB。所以max_connections × work_mem必须小于可用内存。maintenance_work_mem = 1GB
专供 VACUUM、CREATE INDEX、ALTER TABLE 等维护操作使用。默认 64MB,建一个 1 亿行表的索引要 23 分钟;设为 1GB 后,只需 3.7 分钟。计算依据:maintenance_work_mem应为shared_buffers的 1/2 到 1/4,2GBshared_buffers对应 512MB-1GB 最优。effective_cache_size = 10GB
这不是分配内存,而是告诉查询规划器:“系统大概有多少内存可用于缓存数据”。设得太低(如默认 4GB),规划器会低估缓存能力,倾向用 Nested Loop 而非 Hash Join,导致慢查询。设为物理内存的 75%(16GB 内存设 12GB)最准。checkpoint_completion_target = 0.9
控制检查点写入的平滑度。默认 0.5,意味着检查点要在 50% 时间内完成,造成 I/O 尖峰。设为 0.9,让写入均匀分布在 90% 时间内,磁盘 I/O 波动降低 65%。这是对抗“检查点风暴”的核心参数。wal_buffers = 16MB
WAL(预写日志)的内存缓冲区。默认 -1(自动设为shared_buffers/32,约 64MB)。但实测发现,设为 16MB 时 WAL 写入延迟更稳定,尤其在高并发 INSERT 场景。原理是:过大的wal_buffers会导致 fsync 延迟变长,而 16MB 是 Linux 页缓存(4KB)的整数倍,对齐效率最高。default_statistics_target = 500
控制 ANALYZE 收集统计信息的粒度。默认 100,对简单表够用;但对分布不均的字段(如用户等级:90% 是 Lv1,5% 是 Lv10),设为 500 能让规划器更准识别数据倾斜,避免错误选择索引扫描。random_page_cost = 1.1
衡量随机读取 vs 顺序读取的成本。SSD 默认应为 1.1(HDD 是 4.0)。设错会导致规划器放弃索引扫描,强行用顺序扫描,100 万行表查询从 20ms 暴涨到 1200ms。log_statement = 'mod'
记录所有 DDL(CREATE/DROP)和 DML(INSERT/UPDATE/DELETE)语句。默认none,线上问题排查时抓瞎。设为mod后,日志量增加约 15%,但换来的是“谁在什么时候删了这张表”的铁证。log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
日志前缀必须包含%t(时间戳)、%p(进程 ID)、%u(用户)、%d(数据库名)。少了%h(客户端 IP),你永远不知道是哪个应用服务器在狂刷慢查询。
注意:修改
postgresql.conf后,不要直接sudo systemctl restart postgresql。先用sudo systemctl reload postgresql尝试热加载——如果参数不支持热加载(如shared_buffers),它会报错,此时再重启。热加载成功意味着配置生效且无语法错误,这是避免服务中断的关键缓冲。
3.3pg_hba.conf:权限控制的“最后一道门”,写错一行等于裸奔
pg_hba.conf是 PostgreSQL 的防火墙规则,它按顺序匹配,第一条匹配的规则生效,后续规则全部忽略。这是无数安全事件的根源。一个典型错误配置:
# TYPE DATABASE USER ADDRESS METHOD host all all 0.0.0.0/0 md5 host all postgres 127.0.0.1/32 trust表面看,本地postgres用户用trust很方便,但第二行永远不生效!因为第一行0.0.0.0/0已经匹配了所有 IP,包括127.0.0.1。正确顺序必须是“从精确到宽泛”:
# TYPE DATABASE USER ADDRESS METHOD local all postgres peer host all postgres 127.0.0.1/32 md5 host all appuser 192.168.1.0/24 scram-sha-256 host all all 0.0.0.0/0 reject这里local行用peer认证,意味着 Unix socket 连接时,系统用户名必须和数据库用户名一致(sudo -u postgres psql才能进);host行对postgres用户强制md5密码,堵死本地免密漏洞;appuser用更安全的scram-sha-256(PostgreSQL 10+ 支持);最后一行reject是兜底,拒绝所有未明确允许的连接。实操中,我坚持一个原则:任何all出现在DATABASE或USER列,都必须有对应的ADDRESS限制。比如host all all 192.168.1.100/32 md5是安全的,因为只允许一台机器;而host all all 192.168.1.0/24 md5就危险,整个网段都能连。
4. 日常使用与运维:从创建用户到备份恢复的完整闭环
4.1 创建安全用户:为什么CREATE USER永远不够
CREATE USER appuser WITH PASSWORD 'xxx';这条命令创建的用户,拥有登录权限(LOGIN),但没有任何数据库访问权。真正的权限体系是三层嵌套:角色(Role)→ 数据库(Database)→ 模式(Schema)→ 表(Table)。我见过最惨的事故:DBA 执行CREATE ROLE readonly NOINHERIT;后忘记GRANT CONNECT ON DATABASE mydb TO readonly;,结果整个 BI 团队报表全挂,因为连数据库大门都进不去。正确流程是四步:
创建角色并设密码:
CREATE ROLE appuser WITH LOGIN PASSWORD 'StrongPass!2024' NOSUPERUSER NOCREATEDB NOCREATEROLE;NOSUPERUSER是铁律,NOCREATEDB防止用户建库污染主集群。授权连接数据库:
GRANT CONNECT ON DATABASE mydb TO appuser;授权使用模式(通常是
public):\c mydb -- 切换到目标数据库 GRANT USAGE ON SCHEMA public TO appuser;授权表级权限:
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO appuser; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE ON TABLES TO appuser;第二行
ALTER DEFAULT PRIVILEGES是关键:它确保未来新建的表,appuser自动拥有权限,否则每次CREATE TABLE后都要手动GRANT。
实操心得:永远用
psql -U appuser -d mydb -c "SELECT 1;"测试新用户。如果报错FATAL: permission denied for database "mydb",一定是第 2 步漏了;如果报ERROR: permission denied for schema "public",就是第 3 步没做。这种测试 10 秒搞定,比等应用报错再排查快 10 倍。
4.2 备份与恢复:pg_dump、pg_basebackup、WAL 归档的实战选择
备份不是“有没有”,而是“能不能在 5 分钟内恢复”。三种方案适用场景截然不同:
pg_dump(逻辑备份):适合中小规模(< 100GB)、需跨版本迁移、或只要部分表的场景。命令pg_dump -U postgres -F c -v -f /backup/mydb.dump mydb中,-F c生成自定义格式(压缩、支持并行、可选择恢复对象),-v输出详细日志。恢复时pg_restore -U postgres -d mydb /backup/mydb.dump。但注意:pg_dump是“快照备份”,备份期间新事务仍可写入,所以它不保证时间点一致性(Point-in-Time Recovery, PITR)。如果备份耗时 20 分钟,你只能恢复到这 20 分钟内的某个状态,无法精确到秒。pg_basebackup(物理备份):适合大库(> 100GB)、需 PITR 的场景。它拷贝整个数据目录,是字节级精确复制。命令pg_basebackup -U replicator -D /backup/base_20240520 -Ft -z -P -X stream -R中,-Ft生成 tar 格式(易传输),-z压缩,-X stream同时流式传输 WAL,-R自动生成standby.signal文件,为搭建从库铺路。关键点:pg_basebackup必须用具有REPLICATION权限的用户(如replicator),且pg_hba.conf中要有host replication replicator 127.0.0.1/32 scram-sha-256规则。WAL 归档(持续保护):这是
pg_basebackup的搭档。在postgresql.conf中设:archive_mode = on archive_command = 'cp %p /archive/wal/%f && sync'每次 WAL 切换,PostgreSQL 就执行
cp命令把 WAL 文件存到/archive/wal/。配合pg_basebackup的基础备份,你就能恢复到任意一秒——比如pg_rewind或recovery_target_time = '2024-05-20 14:30:00'。但archive_command必须是原子操作:cp后跟sync确保写入磁盘,否则断电时 WAL 丢失,备份就废了。
常见问题:
pg_dump报错FATAL: sorry, too many clients already。这是因为max_connections被占满。解决方案:pg_dump加-j 4参数(并行 4 个 job),减少单次连接时间;或临时ALTER SYSTEM SET max_connections = 300; SELECT pg_reload_conf();。
4.3 监控与诊断:用原生视图揪出性能杀手
PostgreSQL 内置的pg_stat_*视图是免费的性能透视镜。不用装任何第三方工具,就能定位 90% 的慢查询。
揪出最耗时的查询:
SELECT query, total_time, calls, mean_time, rows FROM pg_stat_statements ORDER BY total_time DESC LIMIT 5;total_time是累计耗时(毫秒),mean_time是平均每次执行时间。如果mean_time高但calls低,说明是偶发慢查询;如果calls高且mean_time稳定,就是高频慢查询,必须优化。查看锁等待链:
SELECT blocked_locks.pid AS blocked_pid, blocked_activity.usename AS blocked_user, blocking_locks.pid AS blocking_pid, blocking_activity.usename AS blocking_user, blocked_activity.query AS blocked_query, blocking_activity.query AS current_query FROM pg_catalog.pg_locks blocked_locks JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid JOIN pg_catalog.pg_locks blocking_locks ON blocking_activity.pid = blocking_locks.pid AND blocking_locks.locktype = blocked_locks.locktype JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid WHERE NOT blocked_activity.pid = blocking_activity.pid AND blocked_locks.granted = false;这个查询能直接看到“谁在等谁”,比如
blocking_query是UPDATE users SET status='active' WHERE id=123;,而blocked_query是SELECT * FROM orders WHERE user_id=123;,说明订单查询被用户状态更新锁住了。检测索引使用率:
SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read, idx_tup_fetch FROM pg_stat_all_indexes WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND idx_scan = 0 ORDER BY idx_tup_read DESC;idx_scan = 0表示索引从未被查询使用过,却是idx_tup_read > 0,说明它只在VACUUM或ANALYZE时被读取——这种索引就是冗余的,应该DROP INDEX删除,减少写入开销。
实操技巧:把这三个查询保存为
~/.psqlrc文件中的\set别名,比如\set top_queries 'SELECT ...',之后在psql里直接输入\gexec top_queries就能一键执行,比反复粘贴快得多。
5. 常见问题与避坑指南:那些文档里不会写的血泪教训
5.1 “Connection refused” 的 5 种真实原因及速查表
| 现象 | 根本原因 | 诊断命令 | 解决方案 |
|---|---|---|---|
psql: error: could not connect to server: Connection refused | PostgreSQL 服务未启动 | sudo systemctl status postgresql | sudo systemctl start postgresql,并检查journalctl -u postgresql -n 50查启动日志 |
同样错误,但systemctl status显示 active | postgresql.conf中listen_addresses未包含客户端 IP | sudo grep listen_addresses /etc/postgresql/*/main/postgresql.conf | 改为listen_addresses = 'localhost,192.168.1.100',然后sudo systemctl reload postgresql |
错误依旧,systemctl和listen_addresses都正常 | pg_hba.conf中无匹配规则,或规则顺序错误 | sudo grep -A5 -B5 "host.*all.*all" /etc/postgresql/*/main/pg_hba.conf | 在pg_hba.conf顶部添加host all all 192.168.1.100/32 scram-sha-256,再sudo systemctl reload postgresql |
| 连接 localhost 成功,但连 127.0.0.1 失败 | pg_hba.conf中local行用peer,而host行对127.0.0.1用了md5,但用户没设密码 | sudo -u postgres psql -c "SELECT usename, passwd IS NOT NULL FROM pg_shadow WHERE usename='postgres';" | sudo -u postgres psql -c "ALTER USER postgres PASSWORD 'newpass';" |
| 所有配置都对,但连接超时 | Ubuntu 防火墙ufw拦截了 5432 端口 | sudo ufw status verbose | sudo ufw allow 5432,或sudo ufw disable(测试环境) |
注意:
ufw是 Ubuntu 20.04 默认防火墙,但很多教程忽略它。我帮客户排查时,70% 的“Connection refused”最终都是ufw拦截。记住:sudo ufw status是连接问题的第一检查项。
5.2 “Permission denied” 权限地狱的破解路径
权限错误通常不是一句GRANT能解决的。PostgreSQL 的权限模型像俄罗斯套娃:
操作系统层:
/var/lib/postgresql/12/main目录权限必须是700,属主postgres:postgres。如果误执行sudo chown -R $USER:$USER /var/lib/postgresql,PostgreSQL 启动时会报FATAL: data directory "/var/lib/postgresql/12/main" has group or world access。修复命令:sudo chown -R postgres:postgres /var/lib/postgresql/12/main && sudo chmod 700 /var/lib/postgresql/12/main。数据库连接层:
pg_hba.conf的METHOD字段。trust表示无条件信任(仅限本地开发),md5需密码,scram-sha-256是更强密码协议。如果用户用psql -U appuser -d mydb连接,而pg_hba.conf中对应规则是md5,但appuser密码为空,就会报password authentication failed for user "appuser"。此时sudo -u postgres psql -c "ALTER USER appuser PASSWORD 'xxx';"即可。对象访问层:即使连接成功,
SELECT * FROM users;仍可能报permission denied for table users。这是因为appuser没有SELECT权限。但GRANT SELECT ON users TO appuser;只对当前表生效,新表还得再GRANT。终极解法是ALTER DEFAULT PRIVILEGES FOR ROLE appuser IN SCHEMA public GRANT SELECT ON TABLES TO appuser;,这样以后CREATE TABLE的表,appuser自动有SELECT权。
5.3 “Out of memory” OOM Killer 的无声绞杀
PostgreSQL 不会主动申请超出shared_buffers的内存,但 Linux OOM Killer 会把它当成“内存大户”干掉。现象是sudo systemctl status postgresql显示failed,journalctl -u postgresql里有Out of memory: Kill process 12345 (postgres) score 850 or sacrifice child。根本原因是vm.swappiness设置过高(默认 60),导致内核过度使用 swap。Ubuntu 20.04 上,sudo sysctl vm.swappiness=1是黄金值:只在内存真正不足时才用 swap,避免 PostgreSQL 进程被误杀。永久生效:echo 'vm.swappiness=1' | sudo tee -a /etc/sysctl.conf。另一个关键是overcommit_memory:sudo sysctl vm.overcommit_memory=2,并设vm.overcommit_ratio=80,让内核严格按RAM × overcommit_ratio%计算可分配内存,杜绝虚假承诺。
5.4 DBeaver 连接超时的 3 个隐藏开关
DBeaver 是最常用的 GUI 工具,但它默认配置会和 PostgreSQL 产生微妙冲突:
连接设置 → 网络 → Socket timeout:默认 30 秒,但某些慢查询(如
VACUUM FULL)会超时。建议调到0(永不超时)或300(5 分钟)。**驱动设置 → 编辑驱动设置 → SSL →