← 返回资讯
赵一鸣
产品评测编辑
已审核

PostgreSQL 性能调优:从查询优化到配置参数

title: "PostgreSQL 性能调优:从查询优化到配置参数"

PostgreSQL 性能调优:从查询优化到配置参数

title: "PostgreSQL 性能调优:从查询优化到配置参数"

date: "2026-07-10"

tags: ["PostgreSQL", "数据库", "性能优化", "SQL"]


PostgreSQL 性能调优:从查询优化到配置参数

PostgreSQL 是最强大的开源关系型数据库。但默认配置并不适合生产环境,需要针对性调优。

查询分析

EXPLAIN ANALYZE

SQL
-- 查看查询执行计划
EXPLAIN ANALYZE
SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2024-01-01'
GROUP BY u.name
HAVING COUNT(o.id) > 5;

输出解读:

常见问题

SQL
-- 问题 1: 隐式类型转换导致索引失效
SELECT * FROM users WHERE phone = 13800138000;  -- phone 是 varchar
-- 修复:
SELECT * FROM users WHERE phone = '13800138000';

-- 问题 2: LIKE 前缀通配符无法使用索引
SELECT * FROM users WHERE name LIKE '%张';
-- 修复:使用 pg_trgm 扩展
CREATE EXTENSION pg_trgm;
CREATE INDEX idx_users_name_trgm ON users USING gin (name gin_trgm_ops);

-- 问题 3: OR 条件导致索引失效
SELECT * FROM users WHERE email = 'a@b.com' OR phone = '13800138000';
-- 修复:使用 UNION
SELECT * FROM users WHERE email = 'a@b.com'
UNION
SELECT * FROM users WHERE phone = '13800138000';

索引策略

B-tree 索引(默认)

SQL
-- 单列索引
CREATE INDEX idx_users_email ON users(email);

-- 复合索引(注意列顺序)
CREATE INDEX idx_orders_user_status ON orders(user_id, status);

-- 部分索引(只索引满足条件的行)
CREATE INDEX idx_orders_pending ON orders(created_at)
WHERE status = 'pending';

-- 覆盖索引(包含额外列,避免回表)
CREATE INDEX idx_users_email_name ON users(email) INCLUDE (name);

GIN 索引(全文搜索、JSON)

SQL
-- 全文搜索
CREATE INDEX idx_posts_content ON posts USING gin(to_tsvector('chinese', content));

-- JSON 字段
CREATE INDEX idx_users_metadata ON users USING gin(metadata);

-- 查询
SELECT * FROM posts WHERE to_tsvector('chinese', content) @@ to_tsquery('数据库');
SELECT * FROM users WHERE metadata @> '{"role": "admin"}';

BRIN 索引(时序数据)

SQL
-- 适合时间序列等自然有序的大表
CREATE INDEX idx_logs_created_brin ON logs USING brin(created_at);

配置调优

内存相关

INI
# postgresql.conf

# 共享缓冲区(建议为总内存的 25%)
shared_buffers = 4GB

# 工作内存(每个排序/哈希操作的内存)
work_mem = 64MB

# 维护操作内存
maintenance_work_mem = 1GB

# 有效缓存大小(告诉优化器系统缓存大小)
effective_cache_size = 12GB

WAL 相关

INI
# WAL 缓冲区
wal_buffers = 64MB

# 检查点间隔
checkpoint_completion_target = 0.9
max_wal_size = 4GB
min_wal_size = 1GB

连接相关

INI
# 最大连接数
max_connections = 200

# 使用连接池(推荐 PgBouncer)
# 应用层连接数可以更高

分区表

SQL
-- 按月分区
CREATE TABLE orders (
    id BIGSERIAL,
    user_id BIGINT,
    amount DECIMAL(10, 2),
    created_at TIMESTAMP
) PARTITION BY RANGE (created_at);

-- 创建分区
CREATE TABLE orders_2024_01 PARTITION OF orders
    FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');

CREATE TABLE orders_2024_02 PARTITION OF orders
    FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');

-- 自动创建分区(使用 pg_partman)
CREATE EXTENSION pg_partman;

SELECT partman.create_parent(
    'public.orders',
    'created_at',
    'native',
    'monthly'
);

连接池

INI
# pgbouncer.ini
[databases]
mydb = host=localhost dbname=mydb

[pgbouncer]
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 50
reserve_pool_size = 10

监控查询

SQL
-- 启用 pg_stat_statements
CREATE EXTENSION pg_stat_statements;

-- 查看最慢的查询
SELECT
    query,
    calls,
    total_time,
    mean_time,
    rows
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 20;

-- 查看未使用的索引
SELECT
    schemaname,
    relname,
    indexrelname,
    idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0
ORDER BY pg_relation_size(indexrelid) DESC;

真空和维护

SQL
-- 手动真空
VACUUM ANALYZE users;

-- 查看需要真空的表
SELECT
    relname,
    n_dead_tup,
    last_autovacuum
FROM pg_stat_user_tables
WHERE n_dead_tup > 10000
ORDER BY n_dead_tup DESC;

-- 调整自动真空参数
ALTER TABLE users SET (
    autovacuum_vacuum_scale_factor = 0.01,
    autovacuum_analyze_scale_factor = 0.005
);

PostgreSQL 性能调优是一个持续的过程。定期分析慢查询、监控索引使用情况、调整配置参数,能让数据库保持最佳状态。

473
6759 阅读
5 评论
分享
链接已复制
编辑说明

本文由 MakeSense 编辑团队撰写并审核。文中引用的数据和观点均经过交叉验证,如有疏漏欢迎在评论区指正。最后更新:2026年07月11日 09:02

赵一鸣

产品评测编辑

前产品经理,现专注 AI 工具评测。实测过 30+ 款 AI 产品,擅长横向对比和用户体验分析。

读者评论 5

运营小陈 1周前
转发到团队群了,大家都觉得有参考价值。
回复 点赞 (4)
数据分析师 1周前
数据引用很扎实,建议补充一下近三个月的最新数据。
回复 点赞 (9)
产品经理阿杰 2周前
从产品角度看,这个方向确实有机会,但商业化路径还需要验证。
回复 点赞 (15)
张工 3天前
写得很实在,特别是实测对比那部分,跟我自己的使用感受一致。
回复 点赞 (12)
前端工程师 6天前
代码示例很清晰,直接用到项目里了。
回复 点赞 (6)