PostgreSQL 完全指南:从安装配置到高级管理

PostgreSQL 是世界上最先进的开源关系型数据库管理系统,以其强大的功能、稳定性和可扩展性著称。从简单的 Web 应用到复杂的企业级系统,PostgreSQL 都能提供可靠的数据存储和管理解决方案。本文将系统性地介绍 PostgreSQL 的安装配置、用户权限管理、远程访问控制、表空间操作以及自增 ID 配置,帮助你全面掌握 PostgreSQL 的管理技能。

简介

什么是 PostgreSQL

PostgreSQL(简称 Postgres)是一个功能强大的开源对象关系型数据库系统,由加州大学伯克利分校计算机系开发。PostgreSQL 使用 SQL 作为查询语言,并扩展了 SQL 标准,支持复杂的数据类型和操作。

PostgreSQL 的特点

特性说明
ACID 兼容完整的事务支持,保证数据一致性
可扩展性支持存储过程、触发器、自定义函数
数据类型丰富支持 JSON、数组、几何类型等
索引类型多样B-tree、GIN、GiST、SP-GiST、HASH
高并发优秀的 MVCC 并发控制
跨平台支持 Linux、Windows、macOS
开源采用 PostgreSQL 许可证,完全免费

PostgreSQL vs MySQL vs SQLite

特性PostgreSQLMySQLSQLite
复杂查询★★★★★★★★★☆★★★☆☆
数据完整性★★★★★★★★★☆★★★★☆
并发性能★★★★★★★★★☆★★☆☆☆
易用性★★★☆☆★★★★★★★★★★
适用场景企业级应用Web 应用嵌入式/小型应用

PostgreSQL 适用场景

适合使用 PostgreSQL 的场景:

  • 企业级应用系统
  • 复杂数据查询和分析
  • 需要高并发和高可用性
  • 地理信息系统(GIS)
  • 科学研究和数据分析
  • 需要复杂事务处理的应用

安装与配置

在 Linux 安装 PostgreSQL

Ubuntu/Debian

 1# 添加 PostgreSQL 官方仓库
 2sudo apt-get install wget ca-certificates
 3sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
 4wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
 5
 6# 安装 PostgreSQL 16
 7sudo apt-get update
 8sudo apt-get install postgresql-16 postgresql-client-16
 9
10# 启动服务
11sudo systemctl start postgresql
12sudo systemctl enable postgresql
13
14# 验证安装
15psql --version

CentOS/RHEL

 1# 安装 PostgreSQL 仓库
 2sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-pgdg.rpm
 3
 4# 安装 PostgreSQL 16
 5sudo dnf install -y postgresql16-server postgresql16
 6
 7# 初始化数据库
 8sudo /usr/pgsql-16/bin/postgresql-16-setup initdb
 9
10# 启动服务
11sudo systemctl start postgresql-16
12sudo systemctl enable postgresql-16
13
14# 验证安装
15/usr/pgsql-16/bin/psql --version

在 macOS 安装 PostgreSQL

1# 使用 Homebrew 安装
2brew install postgresql@16
3
4# 启动服务
5brew services start postgresql@16
6
7# 验证安装
8psql --version

在 Windows 安装 PostgreSQL

  1. 访问 PostgreSQL 官网
  2. 下载安装程序(例如 postgresql-16.x-1-windows-x64.exe)
  3. 运行安装程序,按照向导完成安装
  4. 安装完成后,使用 pgAdmin 或命令行工具管理数据库

配置文件位置

PostgreSQL 的配置文件通常位于数据目录下:

平台数据目录
Linux (Debian/Ubuntu)/var/lib/postgresql/16/main/
Linux (CentOS/RHEL)/var/lib/pgsql/16/data/
macOS (Homebrew)/usr/local/var/postgres//opt/homebrew/var/postgresql/
WindowsC:\Program Files\PostgreSQL\16\data\

主要配置文件:

  • postgresql.conf - 主配置文件(监听地址、端口、内存等)
  • pg_hba.conf - 客户端认证配置文件(访问控制)
  • pg_ident.conf - 用户名映射配置文件

数据库操作

创建数据库

 1-- 使用 SQL 命令创建数据库
 2CREATE DATABASE mydb;
 3
 4-- 指定所有者
 5CREATE DATABASE mydb OWNER postgres;
 6
 7-- 设置编码和字符集
 8CREATE DATABASE mydb
 9    OWNER postgres
10    ENCODING 'UTF8'
11    LC_COLLATE 'en_US.UTF-8'
12    LC_CTYPE 'en_US.UTF-8'
13    TEMPLATE template0;
14
15-- 查看数据库列表
16\l
17
18-- 连接到指定数据库
19\c mydb

命令行工具操作

 1# 创建数据库
 2createdb mydb
 3
 4# 连接到数据库
 5psql mydb
 6
 7# 以特定用户身份连接
 8psql -U postgres -d mydb
 9
10# 执行 SQL 文件
11psql -U postgres -d mydb -f schema.sql
12
13# 执行单条 SQL 命令
14psql -U postgres -d mydb -c "SELECT version();"

修改数据库

 1-- 重命名数据库
 2ALTER DATABASE mydb RENAME TO newdb;
 3
 4-- 更改所有者
 5ALTER DATABASE newdb OWNER TO new_owner;
 6
 7-- 修改数据库属性
 8ALTER DATABASE newdb SET default_tablespace = new_tablespace;
 9ALTER DATABASE newdb RESET default_tablespace;
10
11-- 设置连接限制
12ALTER DATABASE newdb CONNECTION LIMIT 100;

删除数据库

 1-- 删除数据库
 2DROP DATABASE mydb;
 3
 4-- 删除数据库(如果存在)
 5DROP DATABASE IF EXISTS mydb;
 6
 7-- 强制断开所有连接后删除
 8SELECT pg_terminate_backend(pid)
 9FROM pg_stat_activity
10WHERE datname = 'mydb'
11AND pid <> pg_backend_pid();
12
13DROP DATABASE mydb;

备份与恢复

使用 pg_dump 备份

 1# 备份单个数据库
 2pg_dump -U postgres mydb > mydb_backup.sql
 3
 4# 备份时压缩
 5pg_dump -U postgres -Fc -f mydb_backup.dump mydb
 6
 7# 只备份结构
 8pg_dump -U postgres -s mydb > schema.sql
 9
10# 只备份数据
11pg_dump -U postgres -a mydb > data.sql
12
13# 备份特定表
14pg_dump -U postgres -t users -t orders mydb > tables_backup.sql

使用 pg_restore 恢复

 1# 从 SQL 文件恢复
 2psql -U postgres -d newdb < mydb_backup.sql
 3
 4# 从自定义格式恢复
 5pg_restore -U postgres -d newdb mydb_backup.dump
 6
 7# 恢复时只恢复结构
 8pg_restore -U postgres -s -d newdb mydb_backup.dump
 9
10# 恢复特定表
11pg_restore -U postgres -t users -t orders -d newdb mydb_backup.dump

用户与权限管理

创建用户和角色

PostgreSQL 中,USERROLE 本质上是相同的,CREATE USER 等价于 CREATE ROLE WITH LOGIN。

 1-- 创建用户(带密码)
 2CREATE USER alice WITH PASSWORD 'SecurePassword123!';
 3
 4-- 创建角色(不带登录权限)
 5CREATE ROLE readonly;
 6
 7-- 创建超级用户
 8CREATE USER admin WITH PASSWORD 'AdminPass123!' SUPERUSER;
 9
10-- 创建带属性的详细用户
11CREATE USER app_user WITH
12    PASSWORD 'AppPass123!'
13    CREATEDB
14    NOCREATEROLE
15    NOINHERIT
16    LOGIN
17    CONNECTION LIMIT 10;
18
19-- 创建角色并授予给其他角色
20CREATE GROUP developers WITH ROLE alice, bob;

修改用户密码

 1-- 修改当前用户密码
 2ALTER USER CURRENT_USER WITH PASSWORD 'NewPassword123!';
 3
 4-- 修改指定用户密码
 5ALTER USER alice WITH PASSWORD 'NewSecurePassword!';
 6
 7-- 使用 psql 命令行修改
 8\password alice
 9-- 系统会提示输入新密码
10
11-- 设置密码过期
12ALTER USER alice VALID UNTIL '2026-12-31';

配置密码加密

postgresql.conf 中配置密码加密方式:

1# 密码加密方式(推荐 scram-sha-256)
2password_encryption = scram-sha-256
3
4# 可选值:
5# - md5:传统 MD5 加密
6# - scram-sha-256:更安全的加密方式(PostgreSQL 10+)

修改后重启 PostgreSQL 服务:

1sudo systemctl restart postgresql

授予权限

 1-- 授予数据库连接权限
 2GRANT CONNECT ON DATABASE mydb TO alice;
 3
 4-- 授予模式使用权限
 5GRANT USAGE ON SCHEMA public TO alice;
 6
 7-- 授予表的所有权限
 8GRANT ALL PRIVILEGES ON TABLE users TO alice;
 9
10-- 授予表的特定权限
11GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE users TO alice;
12
13-- 授予序列权限
14GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO alice;
15
16-- 授予函数权限
17GRANT EXECUTE ON FUNCTION get_user_stats() TO alice;
18
19-- 授予模式下的所有表权限
20GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
21
22-- 授予未来创建的表权限(自动授权)
23ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly;

撤销权限

 1-- 撤销特定权限
 2REVOKE INSERT ON TABLE users FROM alice;
 3
 4-- 撤销所有权限
 5REVOKE ALL PRIVILEGES ON TABLE users FROM alice;
 6
 7-- 撤销角色权限
 8REVOKE readonly FROM alice;
 9
10-- 撤销默认权限
11ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE SELECT ON TABLES FROM readonly;

查看用户权限

 1-- 查看所有用户和角色
 2\du
 3
 4-- 查看当前用户权限
 5SELECT * FROM information_schema.role_table_grants
 6WHERE grantee = current_user;
 7
 8-- 查看表的权限
 9\dp table_name
10
11-- 查看数据库权限
12SELECT datname, datacl FROM pg_database WHERE datname = 'mydb';
13
14-- 查看角色成员
15SELECT * FROM pg_roles;

角色继承和组管理

 1-- 创建组角色
 2CREATE ROLE developers NOLOGIN;
 3
 4-- 创建用户并加入组
 5CREATE USER bob WITH PASSWORD 'BobPass123!' IN ROLE developers;
 6CREATE USER charlie WITH PASSWORD 'CharliePass123!' IN ROLE developers;
 7
 8-- 将已有用户加入组
 9GRANT developers TO alice;
10
11-- 移除用户从组
12REVOKE developers FROM alice;
13
14-- 设置角色权限继承(NOINHERIT 需要显式启用)
15CREATE ROLE dba WITH NOINHERIT LOGIN;
16CREATE ROLE dev WITH INHERIT LOGIN;
17GRANT dba TO dev;
18
19-- 临时激活不继承的角色
20SET ROLE dba;

远程访问控制

配置监听地址

编辑 postgresql.conf 文件:

 1# 监听所有网络接口
 2listen_addresses = '*'
 3
 4# 监听特定 IP 地址
 5# listen_addresses = '192.168.1.100,127.0.0.1'
 6
 7# 修改默认端口(默认 5432)
 8port = 5432
 9
10# 最大连接数
11max_connections = 100

修改后重启服务:

1sudo systemctl restart postgresql

配置客户端认证

编辑 pg_hba.conf 文件来控制客户端访问:

 1# TYPE  DATABASE        USER            ADDRESS                 METHOD
 2
 3# 本地连接
 4local   all             postgres                                peer
 5local   all             all                                     md5
 6
 7# IPv4 本地回环
 8host    all             all             127.0.0.1/32            scram-sha-256
 9
10# IPv6 本地回环
11host    all             all             ::1/128                 scram-sha-256
12
13# 允许特定 IP 段访问(密码认证)
14host    all             all             192.168.1.0/24          scram-sha-256
15
16# 允许只读用户只读访问
17host    mydb            readonly        192.168.1.0/24          scram-sha-256
18
19# 允许 SSL 连接
20hostssl all             all             0.0.0.0/0               scram-sha-256
21
22# 拒绝特定 IP
23host    all             all             10.0.0.0/8              reject

认证方法说明:

方法说明
trust无条件信任,不推荐生产环境
md5MD5 加密密码
scram-sha-256SHA-256 加密,更安全(推荐)
password明文密码传输,不安全
peer使用操作系统用户认证(本地连接)
certSSL 客户端证书认证
reject拒绝连接

修改后重载配置:

1sudo systemctl reload postgresql

配置 SSL/TLS

生成自签名证书(用于测试):

 1# 进入数据目录
 2cd /var/lib/postgresql/16/main/
 3
 4# 生成服务器私钥
 5openssl genrsa -out server.key 2048
 6
 7# 设置私钥权限
 8chmod 600 server.key
 9chown postgres:postgres server.key
10
11# 生成证书签名请求(CSR)
12openssl req -new -key server.key -out server.csr
13
14# 生成自签名证书(有效期 365 天)
15openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

postgresql.conf 中配置 SSL:

 1# 启用 SSL
 2ssl = on
 3
 4# SSL 证书路径
 5ssl_cert_file = 'server.crt'
 6
 7# SSL 私钥路径
 8ssl_key_file = 'server.key'
 9
10# SSL 协议版本
11ssl_protocols = 'TLSv1.2,TLSv1.3'
12
13# SSL 加密套件
14ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'

防火墙配置

Ubuntu/Debian (UFW)

1# 允许 PostgreSQL 端口(默认 5432)
2sudo ufw allow 5432/tcp
3
4# 限制特定 IP 访问
5sudo ufw allow from 192.168.1.0/24 to any port 5432
6
7# 查看防火墙状态
8sudo ufw status

CentOS/RHEL (firewalld)

 1# 添加 PostgreSQL 服务
 2sudo firewall-cmd --permanent --add-service=postgresql
 3
 4# 或者添加端口
 5sudo firewall-cmd --permanent --add-port=5432/tcp
 6
 7# 限制来源 IP
 8sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="5432" accept'
 9
10# 重载防火墙
11sudo firewall-cmd --reload
12
13# 查看规则
14sudo firewall-cmd --list-all

远程连接示例

1# 从远程主机连接
2psql -h 192.168.1.100 -p 5432 -U alice -d mydb
3
4# 使用 SSL 连接
5psql -h 192.168.1.100 -p 5432 -U alice -d mydb sslmode=require
6
7# 查看连接信息
8\conninfo

数据表操作

创建表

 1-- 基本表创建
 2CREATE TABLE users (
 3    id SERIAL PRIMARY KEY,
 4    username VARCHAR(50) NOT NULL UNIQUE,
 5    email VARCHAR(100) NOT NULL,
 6    age INTEGER CHECK (age >= 0 AND age <= 150),
 7    is_active BOOLEAN DEFAULT true,
 8    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
 9);
10
11-- 带外键约束的表
12CREATE TABLE orders (
13    id BIGSERIAL PRIMARY KEY,
14    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
15    order_no VARCHAR(32) NOT NULL UNIQUE,
16    total_amount DECIMAL(10, 2) NOT NULL,
17    status VARCHAR(20) DEFAULT 'pending',
18    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
19);
20
21-- 创建带注释的表
22CREATE TABLE articles (
23    id BIGSERIAL PRIMARY KEY,
24    title VARCHAR(200) NOT NULL,
25    content TEXT,
26    author_id INTEGER REFERENCES users(id),
27    views INTEGER DEFAULT 0,
28    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
29    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
30);
31
32COMMENT ON TABLE articles IS '文章表';
33COMMENT ON COLUMN articles.title IS '文章标题';
34COMMENT ON COLUMN articles.content IS '文章内容';

修改表结构

 1-- 添加列
 2ALTER TABLE users ADD COLUMN phone VARCHAR(20);
 3ALTER TABLE users ADD COLUMN avatar BYTEA;
 4
 5-- 添加带默认值的列
 6ALTER TABLE users ADD COLUMN last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
 7
 8-- 删除列
 9ALTER TABLE users DROP COLUMN phone;
10
11-- 重命名列
12ALTER TABLE users RENAME COLUMN username TO user_name;
13
14-- 修改列类型
15ALTER TABLE users ALTER COLUMN email TYPE VARCHAR(150);
16
17-- 添加约束
18ALTER TABLE users ADD CONSTRAINT check_email CHECK (email LIKE '%@%');
19
20-- 添加唯一约束
21ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (email);
22
23-- 添加外键约束
24ALTER TABLE orders ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id);
25
26-- 删除约束
27ALTER TABLE users DROP CONSTRAINT check_email;
28
29-- 设置列非空
30ALTER TABLE users ALTER COLUMN email SET NOT NULL;
31
32-- 取消列非空
33ALTER TABLE users ALTER COLUMN email DROP NOT NULL;
34
35-- 设置默认值
36ALTER TABLE users ALTER COLUMN age SET DEFAULT 18;
37
38-- 取消默认值
39ALTER TABLE users ALTER COLUMN age DROP DEFAULT;

删除表

 1-- 删除表
 2DROP TABLE orders;
 3
 4-- 删除表(如果存在)
 5DROP TABLE IF EXISTS orders;
 6
 7-- 级联删除相关表
 8DROP TABLE orders CASCADE;
 9
10-- 清空表数据(保留结构)
11TRUNCATE TABLE orders;
12
13-- 清空表并重置序列
14TRUNCATE TABLE orders RESTART IDENTITY CASCADE;

查看表结构

 1-- 查看所有表
 2\dt
 3
 4-- 查看指定表结构
 5\d users
 6
 7-- 查看表详细定义
 8\d+ users
 9
10-- 查看表约束
11\d+ orders
12
13-- 查询表信息
14SELECT
15    table_name,
16    column_name,
17    data_type,
18    is_nullable,
19    column_default
20FROM information_schema.columns
21WHERE table_name = 'users'
22ORDER BY ordinal_position;
23
24-- 查看表大小
25SELECT
26    pg_size_pretty(pg_total_relation_size('users')) AS total_size,
27    pg_size_pretty(pg_relation_size('users')) AS table_size,
28    pg_size_pretty(pg_indexes_size('users')) AS index_size;

重命名表

1-- 重命名表
2ALTER TABLE old_table_name RENAME TO new_table_name;
3
4-- 重命名表(带模式)
5ALTER TABLE public.users RENAME TO user_profiles;

自增ID配置

PostgreSQL 提供了多种实现自增 ID 的方式。

使用 SERIAL 类型

 1-- SMALLINT + 自增(范围:1 到 32767)
 2CREATE TABLE small_data (
 3    id SMALLSERIAL PRIMARY KEY,
 4    name VARCHAR(50)
 5);
 6
 7-- INTEGER + 自增(范围:1 到 2147483647)
 8CREATE TABLE users (
 9    id SERIAL PRIMARY KEY,
10    username VARCHAR(50)
11);
12
13-- BIGINT + 自增(范围:1 到 9223372036854775807)
14CREATE TABLE large_data (
15    id BIGSERIAL PRIMARY KEY,
16    content TEXT
17);

使用 IDENTITY 列(PostgreSQL 10+)

 1-- GENERATED ALWAYS AS IDENTITY(推荐)
 2CREATE TABLE products (
 3    id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
 4    name VARCHAR(100),
 5    price DECIMAL(10, 2)
 6);
 7
 8-- GENERATED BY DEFAULT AS IDENTITY(允许手动插入)
 9CREATE TABLE orders (
10    id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
11    order_no VARCHAR(32),
12    total_amount DECIMAL(10, 2)
13);
14
15-- 带序列选项的 IDENTITY
16CREATE TABLE logs (
17    id BIGINT GENERATED ALWAYS AS IDENTITY (
18        START WITH 1000
19        INCREMENT BY 1
20        NO MINVALUE
21        NO MAXVALUE
22        CACHE 20
23    ) PRIMARY KEY,
24    message TEXT,
25    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
26);

序列管理

 1-- 创建自定义序列
 2CREATE SEQUENCE user_id_seq
 3    START WITH 1
 4    INCREMENT BY 1
 5    NO MINVALUE
 6    NO MAXVALUE
 7    CACHE 1;
 8
 9-- 在表中使用序列
10CREATE TABLE users (
11    id INTEGER PRIMARY KEY DEFAULT nextval('user_id_seq'),
12    username VARCHAR(50)
13);
14
15-- 获取下一个序列值
16SELECT nextval('user_id_seq');
17
18-- 获取当前序列值
19SELECT currval('user_id_seq');
20
21-- 设置序列值
22SELECT setval('user_id_seq', 1000);
23
24-- 重置序列
25ALTER SEQUENCE user_id_seq RESTART WITH 1;
26
27-- 修改序列属性
28ALTER SEQUENCE user_id_seq INCREMENT BY 5;
29ALTER SEQUENCE user_id_seq CACHE 50;
30
31-- 查看序列
32\ds
33
34-- 删除序列
35DROP SEQUENCE IF EXISTS user_id_seq;

重置自增序列

 1-- 方法1:使用 RESTART
 2ALTER SEQUENCE users_id_seq RESTART WITH 1;
 3
 4-- 方法2:使用 setval(设置为最大 ID + 1)
 5SELECT setval('users_id_seq', COALESCE(MAX(id), 0) + 1) FROM users;
 6
 7-- 方法3:重置所有序列为当前最大值
 8DO $$
 9DECLARE
10    table_name TEXT;
11    column_name TEXT;
12    sequence_name TEXT;
13BEGIN
14    FOR table_name, column_name, sequence_name IN
15        SELECT
16            t.table_name,
17            c.column_name,
18            s.sequence_name
19        FROM
20            information_schema.tables t
21            JOIN information_schema.columns c
22                ON t.table_name = c.table_name
23            JOIN information_schema.sequences s
24                ON c.column_default LIKE '%' || s.sequence_name || '%'
25        WHERE
26            t.table_schema = 'public'
27    LOOP
28        EXECUTE format('SELECT setval(%L, COALESCE(MAX(%I), 0) + 1) FROM %I',
29            sequence_name, column_name, table_name);
30    END LOOP;
31END $$;

多表共享序列

 1-- 创建共享序列
 2CREATE SEQUENCE global_id_seq;
 3
 4-- 多个表使用同一序列
 5CREATE TABLE orders (
 6    id INTEGER PRIMARY KEY DEFAULT nextval('global_id_seq'),
 7    order_no VARCHAR(32)
 8);
 9
10CREATE TABLE invoices (
11    id INTEGER PRIMARY KEY DEFAULT nextval('global_id_seq'),
12    invoice_no VARCHAR(32)
13);
14
15-- 现在 orders 和 invoices 的 ID 不会冲突

表空间操作

创建表空间

表空间允许将数据库对象存储在指定的磁盘位置。

 1-- 创建表空间(需要超级用户权限)
 2CREATE TABLESPACE fast_storage LOCATION '/mnt/fast_storage';
 3
 4-- 创建表空间并指定所有者
 5CREATE TABLESPACE slow_storage
 6    OWNER postgres
 7    LOCATION '/mnt/slow_storage';
 8
 9-- 查看表空间
10\db

注意: 创建表空间前,确保目录存在且权限正确:

1# 创建目录
2sudo mkdir -p /mnt/fast_storage
3
4# 设置权限(所有者是 postgres 用户)
5sudo chown postgres:postgres /mnt/fast_storage
6sudo chmod 700 /mnt/fast_storage

使用表空间

 1-- 在指定表空间创建表
 2CREATE TABLE large_data (
 3    id BIGSERIAL PRIMARY KEY,
 4    content TEXT,
 5    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
 6) TABLESPACE slow_storage;
 7
 8-- 将表移动到表空间
 9ALTER TABLE large_data SET TABLESPACE fast_storage;
10
11-- 在指定表空间创建索引
12CREATE INDEX idx_large_data_created ON large_data(created_at)
13    TABLESPACE fast_storage;
14
15-- 将索引移动到表空间
16ALTER INDEX idx_large_data_created SET TABLESPACE slow_storage;

表空间管理

 1-- 重命名表空间
 2ALTER TABLESPACE fast_storage RENAME TO ssd_storage;
 3
 4-- 修改表空间所有者
 5ALTER TABLESPACE slow_storage OWNER TO admin;
 6
 7-- 查看表空间使用情况
 8SELECT
 9    spcname AS tablespace_name,
10    pg_size_pretty(pg_tablespace_size(spcname)) AS size
11FROM pg_tablespace
12WHERE spcname NOT LIKE 'pg_%'
13ORDER BY pg_tablespace_size(spcname) DESC;
14
15-- 查看表空间中的对象
16SELECT
17    schemaname,
18    tablename,
19    tablespace
20FROM pg_tables
21WHERE tablespace IS NOT NULL;

删除表空间

1-- 删除表空间(需要先移除所有对象)
2DROP TABLESPACE IF EXISTS slow_storage;

表空间使用场景

 1-- 场景1:分离热数据和冷数据
 2-- 热数据(频繁访问)放在 SSD
 3CREATE TABLE active_users (
 4    id SERIAL PRIMARY KEY,
 5    data TEXT
 6) TABLESPACE ssd_storage;
 7
 8-- 冷数据(归档数据)放在 HDD
 9CREATE TABLE archived_data (
10    id SERIAL PRIMARY KEY,
11    archive_content TEXT
12) TABLESPACE slow_storage;
13
14-- 场景2:分离索引和数据
15CREATE TABLE products (
16    id SERIAL PRIMARY KEY,
17    name VARCHAR(100),
18    description TEXT
19) TABLESPACE hdd_storage;
20
21-- 索引放在 SSD 提升查询性能
22CREATE INDEX idx_products_name ON products(name)
23    TABLESPACE ssd_storage;
24
25-- 场景3:不同用户数据分离
26CREATE TABLE user_a_data (
27    id SERIAL PRIMARY KEY,
28    data TEXT
29) TABLESPACE user_a_storage;
30
31CREATE TABLE user_b_data (
32    id SERIAL PRIMARY KEY,
33    data TEXT
34) TABLESPACE user_b_storage;

数据操作

插入数据

 1-- 单条插入
 2INSERT INTO users (username, email, age) VALUES ('alice', 'alice@example.com', 25);
 3
 4-- 多条插入
 5INSERT INTO users (username, email, age) VALUES
 6    ('bob', 'bob@example.com', 30),
 7    ('charlie', 'charlie@example.com', 28),
 8    ('diana', 'diana@example.com', 32);
 9
10-- 使用默认值插入
11INSERT INTO users (username, email) VALUES ('eve', 'eve@example.com');
12
13-- 从查询结果插入
14INSERT INTO users (username, email)
15SELECT username, email FROM temp_users WHERE status = 'active';
16
17-- 插入并返回 ID
18INSERT INTO users (username, email) VALUES ('frank', 'frank@example.com')
19RETURNING id;
20
21-- 插入或更新(UPSERT)
22INSERT INTO users (username, email, age) VALUES ('alice', 'new_email@example.com', 26)
23ON CONFLICT (username) DO UPDATE SET
24    email = EXCLUDED.email,
25    age = EXCLUDED.age
26RETURNING id;

查询数据

 1-- 基本查询
 2SELECT * FROM users;
 3
 4-- 查询指定列
 5SELECT id, username, email FROM users;
 6
 7-- 条件查询
 8SELECT * FROM users WHERE age > 25;
 9
10-- 多条件查询
11SELECT * FROM users WHERE age >= 25 AND age <= 35;
12
13-- 范围查询
14SELECT * FROM users WHERE age BETWEEN 25 AND 35;
15
16-- IN 查询
17SELECT * FROM users WHERE username IN ('alice', 'bob', 'charlie');
18
19-- 模糊查询
20SELECT * FROM users WHERE username LIKE 'a%';
21SELECT * FROM users WHERE email LIKE '%@example.com';
22
23-- 排序
24SELECT * FROM users ORDER BY age ASC;
25SELECT * FROM users ORDER BY age DESC, username ASC;
26
27-- 限制结果数量
28SELECT * FROM users LIMIT 5;
29SELECT * FROM users LIMIT 5 OFFSET 2;
30
31-- 去重
32SELECT DISTINCT age FROM users;
33
34-- 聚合查询
35SELECT COUNT(*) FROM users;
36SELECT AVG(age) FROM users;
37SELECT MAX(age), MIN(age) FROM users;
38SELECT SUM(views) FROM articles;
39
40-- 分组查询
41SELECT age, COUNT(*) as count FROM users GROUP BY age HAVING count > 1;

连接查询

 1-- 内连接
 2SELECT u.username, o.order_no, o.total_amount
 3FROM users u
 4INNER JOIN orders o ON u.id = o.user_id;
 5
 6-- 左连接
 7SELECT u.username, o.order_no
 8FROM users u
 9LEFT JOIN orders o ON u.id = o.user_id;
10
11-- 右连接
12SELECT u.username, o.order_no
13FROM users u
14RIGHT JOIN orders o ON u.id = o.user_id;
15
16-- 全连接
17SELECT u.username, o.order_no
18FROM users u
19FULL OUTER JOIN orders o ON u.id = o.user_id;
20
21-- 多表连接
22SELECT u.username, o.order_no, oi.quantity, p.name as product_name
23FROM users u
24JOIN orders o ON u.id = o.user_id
25JOIN order_items oi ON o.id = oi.order_id
26JOIN products p ON oi.product_id = p.id;

更新数据

 1-- 更新单条记录
 2UPDATE users SET email = 'new_alice@example.com' WHERE username = 'alice';
 3
 4-- 更新多条记录
 5UPDATE users SET age = age + 1 WHERE age < 30;
 6
 7-- 批量更新
 8UPDATE articles SET views = views + 1 WHERE id = 1;
 9
10-- 使用 FROM 子句更新
11UPDATE users SET email = new_emails.new_email
12FROM (VALUES ('alice', 'alice_new@example.com')) AS new_emails(username, new_email)
13WHERE users.username = new_emails.username;
14
15-- 返回更新的行
16UPDATE users SET age = age + 1 WHERE username = 'bob' RETURNING *;

删除数据

 1-- 删除单条记录
 2DELETE FROM users WHERE username = 'eve';
 3
 4-- 删除多条记录
 5DELETE FROM users WHERE age < 25;
 6
 7-- 使用子查询删除
 8DELETE FROM orders WHERE user_id IN (SELECT id FROM users WHERE is_active = false);
 9
10-- 返回删除的行
11DELETE FROM users WHERE username = 'bob' RETURNING *;
12
13-- 清空表数据(保留结构)
14TRUNCATE TABLE users;
15
16-- 清空表并重置序列
17TRUNCATE TABLE users RESTART IDENTITY CASCADE;

事务处理

 1-- 开始事务
 2BEGIN;
 3
 4-- 执行多个操作
 5INSERT INTO users (username, email) VALUES ('test', 'test@example.com');
 6UPDATE users SET age = age + 1 WHERE username = 'alice';
 7DELETE FROM users WHERE username = 'eve';
 8
 9-- 提交事务
10COMMIT;
11
12-- 或者回滚事务
13-- ROLLBACK;
14
15-- 保存点
16BEGIN;
17INSERT INTO users (username, email) VALUES ('test1', 'test1@example.com');
18SAVEPOINT my_savepoint;
19INSERT INTO users (username, email) VALUES ('test2', 'test2@example.com');
20-- 回滚到保存点
21ROLLBACK TO my_savepoint;
22COMMIT;

高级特性

索引

 1-- B-tree 索引(默认)
 2CREATE INDEX idx_users_username ON users(username);
 3
 4-- 唯一索引
 5CREATE UNIQUE INDEX idx_users_email ON users(email);
 6
 7-- 复合索引
 8CREATE INDEX idx_users_age_email ON users(age, email);
 9
10-- GIN 索引(用于数组、JSON、全文搜索)
11CREATE INDEX idx_articles_content ON articles USING GIN(to_tsvector('english', content));
12
13-- GiST 索引(用于几何数据、范围)
14CREATE INDEX idx_geo_location ON locations USING GiST(coordinates);
15
16-- 部分索引
17CREATE INDEX idx_active_users ON users(username) WHERE is_active = true;
18
19-- 表达式索引
20CREATE INDEX idx_users_lower_email ON users(LOWER(email));
21
22-- 查看索引
23\di
24
25-- 查看表的索引
26\di users*
27
28-- 分析索引使用
29SELECT * FROM pg_stat_user_indexes WHERE relname = 'users';
30
31-- 删除索引
32DROP INDEX IF EXISTS idx_users_username;
33
34-- 并发创建索引(不锁表)
35CREATE INDEX CONCURRENTLY idx_users_age ON users(age);

视图

 1-- 创建视图
 2CREATE VIEW user_orders AS
 3SELECT
 4    u.id as user_id,
 5    u.username,
 6    u.email,
 7    COUNT(o.id) as order_count,
 8    SUM(o.total_amount) as total_spent
 9FROM users u
10LEFT JOIN orders o ON u.id = o.user_id
11GROUP BY u.id, u.username, u.email;
12
13-- 查询视图
14SELECT * FROM user_orders WHERE total_spent > 1000;
15
16-- 创建可更新视图
17CREATE VIEW active_users AS
18SELECT id, username, email, age
19FROM users
20WHERE is_active = true;
21
22-- 更新可更新视图
23UPDATE active_users SET age = age + 1 WHERE id = 1;
24
25-- 删除视图
26DROP VIEW IF EXISTS user_orders;

物化视图

 1-- 创建物化视图
 2CREATE MATERIALIZED VIEW user_stats AS
 3SELECT
 4    u.id,
 5    u.username,
 6    COUNT(DISTINCT o.id) as order_count,
 7    SUM(o.total_amount) as total_amount
 8FROM users u
 9LEFT JOIN orders o ON u.id = o.user_id
10GROUP BY u.id, u.username;
11
12-- 刷新物化视图
13REFRESH MATERIALIZED VIEW user_stats;
14
15-- 并发刷新(不影响查询)
16REFRESH MATERIALIZED VIEW CONCURRENTLY user_stats;
17
18-- 删除物化视图
19DROP MATERIALIZED VIEW IF EXISTS user_stats;

存储过程和函数

 1-- 创建函数
 2CREATE OR REPLACE FUNCTION get_user_count()
 3RETURNS INTEGER AS $$
 4BEGIN
 5    RETURN (SELECT COUNT(*) FROM users);
 6END;
 7$$ LANGUAGE plpgsql;
 8
 9-- 调用函数
10SELECT get_user_count();
11
12-- 带参数的函数
13CREATE OR REPLACE FUNCTION get_user_by_id(p_id INTEGER)
14RETURNS TABLE(
15    username VARCHAR(50),
16    email VARCHAR(100)
17) AS $$
18BEGIN
19    RETURN QUERY
20    SELECT username, email FROM users WHERE id = p_id;
21END;
22$$ LANGUAGE plpgsql;
23
24-- 调用带参数的函数
25SELECT * FROM get_user_by_id(1);
26
27-- 存储过程(PostgreSQL 11+)
28CREATE OR REPLACE PROCEDURE create_user_with_orders(
29    p_username VARCHAR(50),
30    p_email VARCHAR(100)
31) AS $$
32DECLARE
33    v_user_id INTEGER;
34BEGIN
35    INSERT INTO users (username, email) VALUES (p_username, p_email)
36    RETURNING id INTO v_user_id;
37
38    INSERT INTO orders (user_id, order_no, total_amount)
39    VALUES (v_user_id, 'ORD-' || v_user_id, 0.00);
40
41    COMMIT;
42END;
43$$ LANGUAGE plpgsql;
44
45-- 调用存储过程
46CALL create_user_with_orders('test_user', 'test@example.com');

触发器

 1-- 创建触发器函数
 2CREATE OR REPLACE FUNCTION update_modified_at()
 3RETURNS TRIGGER AS $$
 4BEGIN
 5    NEW.updated_at = CURRENT_TIMESTAMP;
 6    RETURN NEW;
 7END;
 8$$ LANGUAGE plpgsql;
 9
10-- 创建触发器
11CREATE TRIGGER update_articles_modified_at
12BEFORE UPDATE ON articles
13FOR EACH ROW
14EXECUTE FUNCTION update_modified_at();
15
16-- 审计日志触发器
17CREATE TABLE audit_log (
18    id SERIAL PRIMARY KEY,
19    table_name VARCHAR(50),
20    operation VARCHAR(10),
21    old_data JSONB,
22    new_data JSONB,
23    changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
24);
25
26CREATE OR REPLACE FUNCTION audit_trigger()
27RETURNS TRIGGER AS $$
28BEGIN
29    IF TG_OP = 'DELETE' THEN
30        INSERT INTO audit_log (table_name, operation, old_data)
31        VALUES (TG_TABLE_NAME, TG_OP, row_to_json(OLD));
32        RETURN OLD;
33    ELSE
34        INSERT INTO audit_log (table_name, operation, new_data)
35        VALUES (TG_TABLE_NAME, TG_OP, row_to_json(NEW));
36        RETURN NEW;
37    END IF;
38END;
39$$ LANGUAGE plpgsql;
40
41CREATE TRIGGER audit_users
42AFTER INSERT OR UPDATE OR DELETE ON users
43FOR EACH ROW EXECUTE FUNCTION audit_trigger();

性能优化

查询分析

 1-- 分析查询计划
 2EXPLAIN SELECT * FROM users WHERE username = 'alice';
 3
 4-- 实际执行并分析
 5EXPLAIN ANALYZE SELECT * FROM users WHERE username = 'alice';
 6
 7-- 带缓冲区的分析
 8EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM users WHERE username = 'alice';
 9
10-- 格式化输出
11EXPLAIN (ANALYZE, VERBOSE, BUFFERS) SELECT * FROM users WHERE username = 'alice';

配置优化

编辑 postgresql.conf 文件进行性能调优:

 1# 内存设置(根据服务器内存调整)
 2shared_buffers = 256MB              # 系统内存的 25%
 3effective_cache_size = 1GB          # 系统内存的 50-75%
 4work_mem = 16MB                     # 每个排序操作的内存
 5maintenance_work_mem = 128MB        # 维护操作的内存
 6
 7# 连接设置
 8max_connections = 100                # 最大连接数
 9
10# 查询计划设置
11random_page_cost = 1.1             # SSD 使用 1.1,HDD 使用 4.0
12effective_io_concurrency = 200       # SSD 设置较高值
13
14# WAL 设置
15wal_buffers = 16MB
16min_wal_size = 1GB
17max_wal_size = 4GB
18
19# 检查点设置
20checkpoint_completion_target = 0.9
21checkpoint_timeout = 15min
22
23# 日志设置
24log_min_duration_statement = 1000    # 记录执行时间超过 1 秒的查询
25log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '

数据库维护

 1-- 分析表统计信息
 2ANALYZE users;
 3
 4-- 分析所有表
 5ANALYZE;
 6
 7-- 清理死元组(VACUUM)
 8VACUUM users;
 9
10-- 完整清理(分析并清理)
11VACUUM FULL users;
12
13-- 自动清理配置
14ALTER TABLE users SET (autovacuum_enabled = true);
15ALTER TABLE users SET (autovacuum_vacuum_scale_factor = 0.1);
16ALTER TABLE users SET (autovacuum_analyze_scale_factor = 0.05);
17
18-- 重建索引
19REINDEX INDEX idx_users_username;
20
21-- 重建表的所有索引
22REINDEX TABLE users;
23
24-- 并发重建索引(不锁表)
25REINDEX INDEX CONCURRENTLY idx_users_username;

查看性能统计

 1-- 查看慢查询
 2SELECT
 3    query,
 4    calls,
 5    total_time,
 6    mean_time,
 7    max_time
 8FROM pg_stat_statements
 9ORDER BY mean_time DESC
10LIMIT 10;
11
12-- 查看表大小
13SELECT
14    schemaname,
15    tablename,
16    pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS total_size
17FROM pg_tables
18WHERE schemaname = 'public'
19ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
20
21-- 查看索引使用情况
22SELECT
23    schemaname,
24    tablename,
25    indexname,
26    idx_scan,
27    idx_tup_read,
28    idx_tup_fetch
29FROM pg_stat_user_indexes
30WHERE idx_scan = 0
31ORDER BY schemaname, tablename;

常见问题

Q1: 如何重置超级用户密码?

 1# 方法1:使用 pg_ctl 停止服务并以单用户模式启动
 2sudo systemctl stop postgresql
 3
 4# 修改 pg_hba.conf 临时使用 trust 认证
 5sudo vim /etc/postgresql/16/main/pg_hba.conf
 6# 将所有认证方法改为 trust
 7
 8# 以单用户模式启动
 9sudo -u postgres psql
10
11# 修改密码
12ALTER USER postgres WITH PASSWORD 'NewPassword123!';
13
14# 恢复 pg_hba.conf 配置
15# 重启服务
16sudo systemctl start postgresql

Q2: 如何允许远程连接?

  1. 编辑 postgresql.conf
1listen_addresses = '*'
  1. 编辑 pg_hba.conf
1host    all             all             192.168.1.0/24          scram-sha-256
  1. 重启或重载服务:
1sudo systemctl reload postgresql
  1. 配置防火墙:
1sudo ufw allow 5432/tcp

Q3: 如何更改 PostgreSQL 端口?

编辑 postgresql.conf

1port = 5433

重启服务:

1sudo systemctl restart postgresql

连接时指定端口:

1psql -p 5433 -U postgres -d mydb

Q4: 如何查看运行中的查询?

 1-- 查看当前活动查询
 2SELECT
 3    pid,
 4    now() - query_start AS duration,
 5    query,
 6    state
 7FROM pg_stat_activity
 8WHERE state != 'idle';
 9
10-- 查看锁等待
11SELECT
12    l.locktype,
13    l.relation::regclass,
14    l.mode,
15    l.pid,
16    a.query
17FROM pg_locks l
18JOIN pg_stat_activity a ON l.pid = a.pid
19WHERE NOT l.granted;

Q5: 如何终止查询或连接?

1-- 终止查询
2SELECT pg_cancel_backend(pid) FROM pg_stat_activity WHERE query LIKE '%slow_query%';
3
4-- 终止连接
5SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE pid = 12345;

Q6: 如何修改表的所有者?

 1-- 修改表所有者
 2ALTER TABLE users OWNER TO new_owner;
 3
 4-- 修改模式下的所有表
 5DO $$
 6DECLARE
 7    r RECORD;
 8BEGIN
 9    FOR r IN SELECT tablename FROM pg_tables WHERE schemaname = 'public'
10    LOOP
11        EXECUTE 'ALTER TABLE public.' || quote_ident(r.tablename) || ' OWNER TO new_owner';
12    END LOOP;
13END $$;

总结

PostgreSQL 是一个功能强大、稳定可靠的企业级关系型数据库,掌握其管理技能对于构建高质量的应用系统至关重要。

核心要点:

PostgreSQL 特点:

  • ACID 完整的事务支持
  • 丰富的数据类型和索引类型
  • 优秀的并发控制和性能
  • 强大的扩展性(函数、触发器、存储过程)

用户与权限管理:

  1. 使用 CREATE USER/ROLE 创建用户和角色
  2. 使用 GRANT/REVOKE 管理权限
  3. 配置 pg_hba.conf 控制客户端访问
  4. 使用角色继承简化权限管理

远程访问控制:

  1. 修改 postgresql.conflisten_addresses
  2. 配置 pg_hba.conf 设置认证规则
  3. 使用 SSL/TLS 加密连接
  4. 配置防火墙限制访问来源

表空间操作:

  1. 使用 CREATE TABLESPACE 创建表空间
  2. 使用 ALTER TABLE SET TABLESPACE 移动表
  3. 根据访问频率分离热冷数据
  4. 分离索引和数据存储

自增ID配置:

  1. 使用 SERIAL 类型(smallserial, serial, bigserial)
  2. 使用 IDENTITY 列(PostgreSQL 10+,推荐)
  3. 管理序列(CREATE SEQUENCE, ALTER SEQUENCE)
  4. 重置序列(RESTART, setval)

最佳实践:

  1. 定期执行 VACUUM 和 ANALYZE 维护数据库
  2. 使用 EXPLAIN ANALYZE 分析查询性能
  3. 根据硬件配置优化 PostgreSQL 参数
  4. 使用 SSL/TLS 保护远程连接
  5. 遵循最小权限原则配置用户权限
  6. 定期备份数据库
  7. 监控慢查询和性能瓶颈

理解 PostgreSQL 的工作原理和管理技巧,可以帮助我们构建高性能、高可用的数据存储解决方案。

参考资源